DisplayMagician/HeliosDisplayManagement/UIForms/ShortcutForm.cs

723 lines
26 KiB
C#
Raw Normal View History

2017-02-26 19:23:31 +00:00
using System;
using System.Collections.Generic;
using System.Drawing.IconLib;
using System.Drawing;
2017-02-26 19:23:31 +00:00
using System.IO;
using System.Linq;
2017-02-26 19:23:31 +00:00
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using HeliosPlus.Resources;
using HeliosPlus.Shared;
using HeliosPlus.GameLibraries;
using NvAPIWrapper.Native.GPU;
2017-02-26 19:23:31 +00:00
namespace HeliosPlus.UIForms
2017-02-26 19:23:31 +00:00
{
public partial class ShortcutForm : Form
{
List<SteamGame> _allSteamGames;
2017-02-26 19:23:31 +00:00
public ShortcutForm()
{
InitializeComponent();
}
public ShortcutForm(Profile profile) : this()
{
Profile = profile;
}
public string ProcessNameToMonitor
2017-02-26 19:23:31 +00:00
{
get
{
if (rb_switch_temp.Checked && rb_standalone.Checked) {
if (rb_wait_executable.Checked)
{
return txt_process_name.Text;
}
}
return string.Empty;
}
2017-08-07 16:38:48 +00:00
set
{
// We we're setting this entry, then we want to set it to a particular entry
txt_process_name.Text = value;
rb_wait_executable.Checked = true;
2017-08-07 16:38:48 +00:00
}
2017-02-26 19:23:31 +00:00
}
public Profile Profile
{
get => dv_profile.Profile;
set
{
// Check the profile is valid
// Create an array of display profiles we have
var profiles = Profile.GetAllProfiles().ToArray();
// Check if the user supplied a --profile option using the profiles' ID
var profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.Id.Equals(value.Id, StringComparison.InvariantCultureIgnoreCase)) : -1;
// If the profileID wasn't there, maybe they used the profile name?
if (profileIndex == -1)
{
// Try and lookup the profile in the profiles' Name fields
profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.Name.StartsWith(value.Name, StringComparison.InvariantCultureIgnoreCase)) : -1;
}
// If the profileID still isn't there, then raise the alarm
if (profileIndex == -1)
{
MessageBox.Show(
$"ShortcutForm: Couldn't find Profile Name or ID supplied to Profile propoerty.",
Language.Executable,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
dv_profile.Profile = value;
}
}
public string ExecutableNameAndPath
2017-02-26 19:23:31 +00:00
{
get => rb_switch_temp.Checked && rb_launcher.Checked ? txt_executable.Text : string.Empty;
2017-02-26 19:23:31 +00:00
set
{
if (File.Exists(txt_executable.Text))
2017-02-26 19:23:31 +00:00
{
rb_switch_temp.Checked = true;
rb_launcher.Checked = true;
2017-02-26 19:23:31 +00:00
txt_executable.Text = value;
}
}
}
public uint ExecutableTimeout
2018-10-20 00:27:25 +00:00
{
get
{
if (rb_wait_executable.Checked)
{
return (uint)nud_timeout_executable.Value;
}
return 0;
}
set
{
nud_timeout_executable.Value = value;
}
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
public string ExecutableArguments
2017-02-26 19:23:31 +00:00
{
get => cb_args_executable.Checked ? txt_args_executable.Text : string.Empty;
2017-02-26 19:23:31 +00:00
set
{
txt_args_executable.Text = value;
cb_args_executable.Checked = true;
2017-02-26 19:23:31 +00:00
}
}
public uint GameAppId
2017-08-07 16:38:48 +00:00
{
get => rb_switch_temp.Checked && rb_launcher.Checked ? (uint) Convert.ToInt32(txt_game_id.Text) : 0;
set
{
rb_switch_temp.Checked = true;
rb_launcher.Checked = true;
txt_game_id.Text = value.ToString();
}
2017-08-07 16:38:48 +00:00
}
public string GameName
2017-02-26 19:23:31 +00:00
{
get => rb_switch_temp.Checked && rb_launcher.Checked ? txt_game_name.Text : string.Empty;
2017-02-26 19:23:31 +00:00
set
{
rb_switch_temp.Checked = true;
rb_launcher.Checked = true;
txt_game_name.Text = value;
2017-02-26 19:23:31 +00:00
}
}
public SupportedGameLibrary GameLibrary
2017-02-26 19:23:31 +00:00
{
get
{
if (rb_switch_temp.Checked && rb_launcher.Checked)
{
if (txt_game_launcher.Text.Contains("Steam"))
{
return SupportedGameLibrary.Steam;
}
else if (txt_game_launcher.Text.Contains("Uplay"))
{
return SupportedGameLibrary.Uplay;
}
}
return SupportedGameLibrary.Unknown;
}
set
2017-02-26 19:23:31 +00:00
{
rb_switch_temp.Checked = true;
rb_launcher.Checked = true;
switch (value)
2018-10-20 00:27:25 +00:00
{
case SupportedGameLibrary.Steam:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibrary), SupportedGameLibrary.Steam);
break;
case SupportedGameLibrary.Uplay:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibrary), SupportedGameLibrary.Uplay);
break;
2018-10-20 00:27:25 +00:00
}
// TODO - If SupportedGameLibrary.Unknown; then we need to show an error message.
}
}
2018-10-20 00:27:25 +00:00
public uint GameTimeout
{
get
{
if (rb_switch_temp.Checked && rb_launcher.Checked)
2018-10-20 00:27:25 +00:00
{
return (uint)nud_timeout_game.Value;
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
return 0;
}
set
{
nud_timeout_game.Value = value;
2017-02-26 19:23:31 +00:00
}
}
public string GameArguments
{
get => cb_args_game.Checked ? txt_args_game.Text : string.Empty;
set
{
txt_args_game.Text = value;
cb_args_game.Checked = true;
}
}
2017-02-26 19:23:31 +00:00
private void btn_app_executable_Click(object sender, EventArgs e)
{
if (dialog_open.ShowDialog(this) == DialogResult.OK)
2018-10-20 00:27:25 +00:00
{
if (File.Exists(dialog_open.FileName) && Path.GetExtension(dialog_open.FileName) == @".exe")
2017-02-26 19:23:31 +00:00
{
txt_executable.Text = dialog_open.FileName;
dialog_open.FileName = string.Empty;
}
else
{
MessageBox.Show(
Language.Selected_file_is_not_a_valid_executable_file,
Language.Executable,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
}
2017-08-07 16:38:48 +00:00
private void btn_save_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.None;
2018-10-20 00:27:25 +00:00
2017-08-07 16:38:48 +00:00
try
{
// Set the Shortcut save folder to the Desktop as that's where people will want it most likely
dialog_save.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// Try to set up some sensible suggestions for the Shortcut name
if (rb_switch_perm.Checked)
{
dialog_save.FileName = Profile.Name;
}
else
{
if (rb_standalone.Checked)
{
dialog_save.FileName = String.Concat(Path.GetFileNameWithoutExtension(ExecutableNameAndPath),@" (", Profile.Name, @")");
}
else
{
dialog_save.FileName = String.Concat(GameName, @" (", Profile.Name, @")");
}
}
// Show the Save Shortcut window
2017-08-07 16:38:48 +00:00
if (dialog_save.ShowDialog(this) == DialogResult.OK)
{
if (CreateShortcut(dialog_save.FileName))
2018-10-20 00:27:25 +00:00
{
2017-08-07 16:38:48 +00:00
MessageBox.Show(
Language.Shortcut_placed_successfully,
2017-08-07 16:38:48 +00:00
Language.Shortcut,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
2018-10-20 00:27:25 +00:00
}
2017-08-07 16:38:48 +00:00
else
2018-10-20 00:27:25 +00:00
{
2017-08-07 16:38:48 +00:00
MessageBox.Show(
Language.Failed_to_create_the_shortcut_Unexpected_exception_occurred,
Language.Shortcut,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
2018-10-20 00:27:25 +00:00
}
2017-08-07 16:38:48 +00:00
dialog_save.FileName = string.Empty;
DialogResult = DialogResult.OK;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Language.Shortcut, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
2017-02-26 19:23:31 +00:00
// ReSharper disable once FunctionComplexityOverflow
2017-08-07 16:38:48 +00:00
// ReSharper disable once CyclomaticComplexity
2017-02-26 19:23:31 +00:00
private bool CreateShortcut(string fileName)
{
string programName = Path.GetFileNameWithoutExtension(txt_executable.Text);
string shortcutDescription = string.Empty;
Icon shortcutIcon = null;
string shortcutIconFileName = string.Empty;
2017-02-26 19:23:31 +00:00
var args = new List<string>
{
// Add the SwitchProfile command as the first argument to start to switch to another profile
$"{HeliosStartupAction.SwitchProfile}"
2017-02-26 19:23:31 +00:00
};
2018-10-20 00:27:25 +00:00
// Only add the rest of the options if the temporary switch radio button is set
if (rb_switch_temp.Checked)
2017-02-26 19:23:31 +00:00
{
// Only add this set of options if the standalone programme radio button is set
2017-02-26 19:23:31 +00:00
if (rb_standalone.Checked)
{
// Doublecheck the Executable text field is filled in
if (string.IsNullOrWhiteSpace(ExecutableNameAndPath))
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
throw new Exception(Language.Executable_address_can_not_be_empty);
2018-10-20 00:27:25 +00:00
}
// Doublecheck the Executable text field is a path to a real file
if (!File.Exists(ExecutableNameAndPath))
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
throw new Exception(Language.Executable_file_not_found);
2018-10-20 00:27:25 +00:00
}
// Add the executable command and the executable name to the shortcut arguments
args.Add($"execute \"{ExecutableNameAndPath}\"");
2018-10-20 00:27:25 +00:00
// Add the Profile Name as the first option (use that rather than ID - though ID still will work!)
args.Add($"--profile \"{Profile.Name}\"");
// Check that the wait for executable radiobutton is on
if (rb_wait_executable.Checked)
2017-02-26 19:23:31 +00:00
{
// Doublecheck the process name has text in it
if (!string.IsNullOrWhiteSpace(ProcessNameToMonitor))
{
// Add the waitfor argument and the process name to the shortcut arguments
args.Add($"--waitfor \"{ProcessNameToMonitor}\"");
}
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
// Add the timeout argument and the timeout duration in seconds to the shortcut arguments
args.Add($"--timeout {ExecutableTimeout}");
if (cb_args_executable.Checked)
{
args.Add($"--arguments \"{ExecutableArguments}\"");
}
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Executing_application_with_profile, programName, Profile.Name);
// Work out the name of the shortcut we'll save.
shortcutIconFileName = Path.Combine(Program.ShortcutIconCachePath, String.Concat(@"executable-", Path.GetFileNameWithoutExtension(ExecutableNameAndPath), @".ico"));
2018-10-20 00:27:25 +00:00
// Grab an icon for the selected executable
2017-02-26 19:23:31 +00:00
try
{
// We'll first try to extract the Icon from the executable the user provided
shortcutIcon = Icon.ExtractAssociatedIcon(ExecutableNameAndPath);
2017-02-26 19:23:31 +00:00
}
2017-08-07 16:38:48 +00:00
catch (Exception)
2017-02-26 19:23:31 +00:00
{
// but if that doesn't work, then we use our own one.
shortcutIcon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
2017-02-26 19:23:31 +00:00
}
}
// Only add the rest of the options if the temporary switch radio button is set
// and if the game launching radio button is set
else if (rb_launcher.Checked)
2017-02-26 19:23:31 +00:00
{
// TODO need to make this work so at least one game library is installed
// i.e. if (!SteamGame.SteamInstalled && !UplayGame.UplayInstalled )
if (GameLibrary == SupportedGameLibrary.Steam)
2018-10-20 00:27:25 +00:00
{
if (!SteamGame.SteamInstalled)
{
throw new Exception(Language.Steam_is_not_installed);
}
2018-10-20 00:27:25 +00:00
List<SteamGame> allSteamGames = SteamGame.GetAllInstalledGames();
SteamGame steamGameToRun = null;
foreach (SteamGame steamGameToCheck in allSteamGames)
{
if (steamGameToCheck.GameId == GameAppId)
{
steamGameToRun = steamGameToCheck;
break;
}
}
shortcutIcon = steamGameToRun.GameIcon;
2018-10-20 00:27:25 +00:00
// Work out the name of the shortcut we'll save.
shortcutIconFileName = Path.Combine(Program.ShortcutIconCachePath, String.Concat(@"steam-", GameAppId.ToString(), @".ico"));
args.Add($"--steam {GameAppId}");
}
else if (GameLibrary == SupportedGameLibrary.Uplay)
2018-10-20 00:27:25 +00:00
{
if (!UplayGame.UplayInstalled)
2017-02-26 19:23:31 +00:00
{
throw new Exception(Language.Steam_is_not_installed);
2017-02-26 19:23:31 +00:00
}
List<UplayGame> allUplayGames = UplayGame.GetAllInstalledGames();
UplayGame uplayGameToRun = null;
foreach (UplayGame uplayGameToCheck in allUplayGames)
2017-02-26 19:23:31 +00:00
{
if (uplayGameToCheck.GameId == GameAppId)
{
uplayGameToRun = uplayGameToCheck;
break;
}
2017-02-26 19:23:31 +00:00
}
shortcutIcon = uplayGameToRun.GameIcon;
// Work out the name of the shortcut we'll save.
shortcutIconFileName = Path.Combine(Program.ShortcutIconCachePath, String.Concat(@"uplay-", GameAppId.ToString(), @".ico"));
args.Add($"--uplay {GameAppId}");
2018-10-20 00:27:25 +00:00
}
// Add the Profile Name as the first option (use that rather than ID - though ID still will work!)
args.Add($"--profile \"{Profile.Name}\"");
// Add the game timeout argument and the timeout duration in seconds to the shortcut arguments
args.Add($"--timeout {GameTimeout}");
if (cb_args_game.Checked)
2018-10-20 00:27:25 +00:00
{
args.Add($"--arguments \"{GameArguments}\"");
2018-10-20 00:27:25 +00:00
}
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Executing_application_with_profile, GameName, Profile.Name);
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
}
// Only add the rest of the options if the permanent switch radio button is set
2017-02-26 19:23:31 +00:00
else
{
// Add the action switch to make the permanent switch to a different profile
args.Add($"permanent");
// Add the Profile Name as the first option (use that rather than ID - though ID still will work!)
args.Add($"--profile \"{Profile.Name}\"");
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Switching_display_profile_to_profile, Profile.Name);
// Work out the name of the shortcut we'll save.
shortcutIconFileName = Path.Combine(Program.ShortcutIconCachePath, String.Concat(@"permanent-", Profile.Name, @".ico"));
2018-10-20 00:27:25 +00:00
// Grab an icon for the selected profile
2017-02-26 19:23:31 +00:00
try
{
MultiIcon profileMultiIcon = new ProfileIcon(Profile).ToIcon();
shortcutIcon = profileMultiIcon[0].Icon;
2017-02-26 19:23:31 +00:00
}
catch
{
// but if that doesn't work, then we use our own one.
shortcutIcon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
2017-02-26 19:23:31 +00:00
}
}
// Save the Icon to the Shortcut Icon cache as the Shortcut will need to refer to it.
if (!File.Exists(shortcutIconFileName))
{
using (StreamWriter fs = File.AppendText(shortcutIconFileName))
shortcutIcon.Save(fs.BaseStream);
}
// Now we are ready to create a shortcut based on the filename the user gave us
2017-02-26 19:23:31 +00:00
fileName = Path.ChangeExtension(fileName, @"lnk");
2018-10-20 00:27:25 +00:00
// If the user supplied a file
2017-02-26 19:23:31 +00:00
if (fileName != null)
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
try
{
// Remove the old file to replace it
if (File.Exists(fileName))
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
File.Delete(fileName);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
// Actually create the shortcut!
2017-02-26 19:23:31 +00:00
var wshShellType = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8"));
dynamic wshShell = Activator.CreateInstance(wshShellType);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
try
{
var shortcut = wshShell.CreateShortcut(fileName);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
try
{
shortcut.TargetPath = Application.ExecutablePath;
shortcut.Arguments = string.Join(" ", args);
shortcut.Description = shortcutDescription;
2017-02-26 19:23:31 +00:00
shortcut.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath) ??
string.Empty;
2018-10-20 00:27:25 +00:00
shortcut.IconLocation = shortcutIconFileName;
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
shortcut.Save();
}
finally
{
Marshal.FinalReleaseComObject(shortcut);
}
}
finally
{
Marshal.FinalReleaseComObject(wshShell);
}
}
catch
{
// Clean up a failed attempt
if (File.Exists(fileName))
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
File.Delete(fileName);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
}
// Return a status on how it went
// true if it was a success or false if it was not
2018-10-20 00:27:25 +00:00
return fileName != null && File.Exists(fileName);
2017-02-26 19:23:31 +00:00
}
private void txt_executable_TextChanged(object sender, EventArgs e)
{
try
{
txt_process_name.Text = Path.GetFileNameWithoutExtension(txt_executable.Text)?.ToLower() ?? txt_process_name.Text;
2017-02-26 19:23:31 +00:00
}
catch
{
// ignored
}
}
private void rb_switch_perm_CheckedChanged(object sender, EventArgs e)
{
if (rb_switch_perm.Checked)
{
// Disable the Temporary Group
g_temporary.Enabled = false;
}
}
private void rb_switch_temp_CheckedChanged(object sender, EventArgs e)
{
if (rb_switch_temp.Checked)
{
// Enable the Temporary Group
g_temporary.Enabled = true;
}
}
private void label1_Click(object sender, EventArgs e)
{
}
private void label7_Click(object sender, EventArgs e)
{
}
private void rb_standalone_CheckedChanged(object sender, EventArgs e)
{
if (rb_standalone.Checked)
{
// Enable the Standalone Panel
p_standalone.Enabled = true;
// Disable the Game Panel
p_game.Enabled = false;
}
}
private void rb_launcher_CheckedChanged(object sender, EventArgs e)
{
if (rb_launcher.Checked)
{
// Enable the Game Panel
p_game.Enabled = true;
// Disable the Standalone Panel
p_standalone.Enabled = false;
}
}
private void cb_args_executable_CheckedChanged(object sender, EventArgs e)
{
// Disable the Process Name Text field
if (cb_args_executable.Checked)
{
// Enable the Executable Arguments Text field
txt_args_executable.Enabled = true;
}
else
{
// Disable the Executable Arguments Text field
txt_args_executable.Enabled = false;
}
}
private async void ShortcutForm_Load(object sender, EventArgs e)
{
// Set the Profile name
lbl_profile.Text = $"Selected Profile: {dv_profile.Profile?.Name ?? Language.None}";
// Start finding the games and loading the Games ListView
List<SteamGame> allSteamGames = SteamGame.GetAllInstalledGames();
_allSteamGames = allSteamGames;
foreach (var game in allSteamGames.OrderBy(game => game.GameName))
{
//var iconAddress = await game.GetIcon();
il_games.Images.Add(game.GameIcon);
if (!Visible)
{
return;
}
lv_games.Items.Add(new ListViewItem
{
Text = game.GameName,
Tag = game,
ImageIndex = il_games.Images.Count - 1
});
}
}
private void rb_wait_process_CheckedChanged(object sender, EventArgs e)
{
if (rb_wait_process.Checked)
{
// Enable the Process Name Text field
txt_process_name.Enabled = true;
} else
{
txt_process_name.Enabled = false;
}
}
private void rb_wait_executable_CheckedChanged(object sender, EventArgs e)
{
if (rb_wait_executable.Checked)
{
// Disable the Process Name Text field
txt_process_name.Enabled = false;
} else
{
txt_process_name.Enabled = true;
}
}
private void btn_app_process_Click(object sender, EventArgs e)
{
if (dialog_open.ShowDialog(this) == DialogResult.OK)
{
if (File.Exists(dialog_open.FileName) && Path.GetExtension(dialog_open.FileName) == @".exe")
{
txt_process_name.Text = dialog_open.FileName;
dialog_open.FileName = string.Empty;
}
else
{
MessageBox.Show(
Language.Selected_file_is_not_a_valid_executable_file,
Language.Executable,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
}
}
private void cb_args_game_CheckedChanged(object sender, EventArgs e)
{
if (cb_args_game.Checked)
{
txt_args_game.Enabled = true;
} else
{
txt_args_game.Enabled = false;
}
}
private void btn_choose_game_Click(object sender, EventArgs e)
{
if (lv_games.SelectedItems.Count > 0)
{
txt_game_name.Text = lv_games.SelectedItems[0].Text;
foreach (SteamGame game in _allSteamGames)
{
if (game.GameName == txt_game_name.Text)
{
txt_game_launcher.Text = game.GameLibrary.ToString();
txt_game_id.Text = game.GameId.ToString();
}
}
}
}
2017-02-26 19:23:31 +00:00
}
}