mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
[WIP] Moving Shortcut run logic to repo
Moved the shortcut running logic from the main Program into the ShortcutRepository so that it can be used from the Shortcut Library UI as well as from the commandline. It's marked as WIP because I also moved the ApplyingChangesForm and accompanying ApplyTopos/ApplyProfiles logic and I broke it. It needs refactoring and hopefully simplifying but I need to work on that next!
This commit is contained in:
@ -1,7 +1,12 @@
|
||||
using HeliosPlus.Shared;
|
||||
using HeliosPlus.GameLibraries;
|
||||
using HeliosPlus.InterProcess;
|
||||
using HeliosPlus.Resources;
|
||||
using HeliosPlus.Shared;
|
||||
using HeliosPlus.UIForms;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.IconLib;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@ -9,6 +14,7 @@ using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@ -434,6 +440,278 @@ namespace HeliosPlus
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once CyclomaticComplexity
|
||||
public static void RunShortcut(ShortcutItem shortcutToUse)
|
||||
{
|
||||
// Do some validation to make sure the shortcut is sensible
|
||||
// And that we have enough to try and action within the shortcut
|
||||
// (in other words check everything in the shortcut is still valid)
|
||||
(bool valid, string reason) = shortcutToUse.IsValid();
|
||||
if (!valid)
|
||||
{
|
||||
throw new Exception(string.Format("Unable to run the shortcut '{0}': {1}", shortcutToUse.Name, reason));
|
||||
}
|
||||
|
||||
// Remember the profile we are on now
|
||||
ProfileItem rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
|
||||
// Try to change to the wanted profile
|
||||
if (!ProfileRepository.ApplyProfile(shortcutToUse.ProfileToUse))
|
||||
{
|
||||
throw new Exception(Language.Cannot_change_active_profile);
|
||||
}
|
||||
|
||||
// Now run the pre-start applications
|
||||
// TODO: Add the prestart applications
|
||||
|
||||
// Now start the main game, and wait if we have to
|
||||
if (shortcutToUse.Category.Equals(ShortcutCategory.Application))
|
||||
{
|
||||
// Start the executable
|
||||
Process process = null;
|
||||
if (shortcutToUse.ExecutableArgumentsRequired)
|
||||
process = System.Diagnostics.Process.Start(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments);
|
||||
else
|
||||
process = System.Diagnostics.Process.Start(shortcutToUse.ExecutableNameAndPath);
|
||||
|
||||
// Create a list of processes to monitor
|
||||
Process[] processesToMonitor = Array.Empty<Process>();
|
||||
|
||||
// Work out if we are monitoring another process other than the main executable
|
||||
if (shortcutToUse.ProcessNameToMonitorUsesExecutable)
|
||||
{
|
||||
// If we are monitoring the same executable we started, then lets do that
|
||||
processesToMonitor = new[] { process };
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now wait a little while for all the processes we want to monitor to start up
|
||||
var ticks = 0;
|
||||
while (ticks < shortcutToUse.ExecutableTimeout * 1000)
|
||||
{
|
||||
// Look for the processes with the ProcessName we want (which in Windows is the filename without the extension)
|
||||
processesToMonitor = System.Diagnostics.Process.GetProcessesByName(Path.GetFileNameWithoutExtension(shortcutToUse.DifferentExecutableToMonitor));
|
||||
|
||||
// TODO: Fix this logic error that will only ever wait for the first process....
|
||||
if (processesToMonitor.Length > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(300);
|
||||
ticks += 300;
|
||||
}
|
||||
|
||||
// If none started up before the timeout, then ignore the
|
||||
if (processesToMonitor.Length == 0)
|
||||
{
|
||||
processesToMonitor = new[] { process };
|
||||
}
|
||||
}
|
||||
|
||||
// Store the process to monitor for later
|
||||
IPCService.GetInstance().HoldProcessId = processesToMonitor.FirstOrDefault()?.Id ?? 0;
|
||||
IPCService.GetInstance().Status = InstanceStatus.OnHold;
|
||||
|
||||
// Add a status notification icon in the status area
|
||||
NotifyIcon notify = null;
|
||||
try
|
||||
{
|
||||
notify = new NotifyIcon
|
||||
{
|
||||
Icon = Properties.Resources.HeliosPlus,
|
||||
Text = string.Format(
|
||||
Language.Waiting_for_the_0_to_terminate,
|
||||
processesToMonitor[0].ProcessName),
|
||||
Visible = true
|
||||
};
|
||||
Application.DoEvents();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ShortcutItem/Run exception: {ex.Message}: {ex.InnerException}");
|
||||
// ignored
|
||||
}
|
||||
|
||||
// Wait for the monitored process to exit
|
||||
foreach (var p in processesToMonitor)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ShortcutItem/Run exception 2: {ex.Message}: {ex.InnerException}");
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the status notification icon from the status area
|
||||
// once we've existed the game
|
||||
if (notify != null)
|
||||
{
|
||||
notify.Visible = false;
|
||||
notify.Dispose();
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
}
|
||||
else if (shortcutToUse.Category.Equals(ShortcutCategory.Game))
|
||||
{
|
||||
// If the game is a Steam Game we check for that
|
||||
if (shortcutToUse.GameLibrary.Equals(SupportedGameLibrary.Steam))
|
||||
{
|
||||
// We now need to get the SteamGame info
|
||||
SteamGame steamGameToRun = SteamLibrary.GetSteamGame(shortcutToUse.GameAppId);
|
||||
|
||||
// If the GameAppID matches a Steam game, then lets run it
|
||||
if (steamGameToRun is SteamGame)
|
||||
{
|
||||
// Prepare to start the steam game using the URI interface
|
||||
// as used by Steam for it's own desktop shortcuts.
|
||||
var address = $"steam://rungameid/{steamGameToRun.GameId}";
|
||||
if (shortcutToUse.GameArgumentsRequired)
|
||||
{
|
||||
address += "/" + shortcutToUse.GameArguments;
|
||||
}
|
||||
|
||||
// Start the URI Handler to run Steam
|
||||
var steamProcess = System.Diagnostics.Process.Start(address);
|
||||
|
||||
// Wait for Steam game to update if needed
|
||||
var ticks = 0;
|
||||
while (ticks < shortcutToUse.GameTimeout * 1000)
|
||||
{
|
||||
if (steamGameToRun.IsRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(300);
|
||||
|
||||
if (!steamGameToRun.IsUpdating)
|
||||
{
|
||||
ticks += 300;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the Steam Process ID for later
|
||||
IPCService.GetInstance().HoldProcessId = steamProcess?.Id ?? 0;
|
||||
IPCService.GetInstance().Status = InstanceStatus.OnHold;
|
||||
|
||||
// Add a status notification icon in the status area
|
||||
NotifyIcon notify = null;
|
||||
try
|
||||
{
|
||||
notify = new NotifyIcon
|
||||
{
|
||||
Icon = Properties.Resources.HeliosPlus,
|
||||
Text = string.Format(
|
||||
Language.Waiting_for_the_0_to_terminate,
|
||||
steamGameToRun.GameName),
|
||||
Visible = true
|
||||
};
|
||||
Application.DoEvents();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Program/SwitchToSteamGame exception: {ex.Message}: {ex.InnerException}");
|
||||
// ignored
|
||||
}
|
||||
|
||||
// Wait for the game to exit
|
||||
if (steamGameToRun.IsRunning)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!steamGameToRun.IsRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the status notification icon from the status area
|
||||
// once we've existed the game
|
||||
if (notify != null)
|
||||
{
|
||||
notify.Visible = false;
|
||||
notify.Dispose();
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// If the game is a Uplay Game we check for that
|
||||
/*else if (GameLibrary.Equals(SupportedGameLibrary.Uplay))
|
||||
{
|
||||
// We need to look up details about the game
|
||||
if (!UplayGame.IsInstalled(GameAppId))
|
||||
{
|
||||
return (false, string.Format("The Uplay Game with AppID '{0}' is not installed on this computer.", GameAppId));
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Change back to the original profile if it is different
|
||||
if (!ProfileRepository.IsActiveProfile(rollbackProfile))
|
||||
{
|
||||
if (!ProfileRepository.ApplyProfile(rollbackProfile))
|
||||
{
|
||||
throw new Exception(Language.Cannot_change_active_profile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool ChangeToProfile(ProfileItem profile)
|
||||
{
|
||||
// If we're already on the wanted profile then no need to change!
|
||||
if (ProfileRepository.IsActiveProfile(profile))
|
||||
return true;
|
||||
|
||||
var instanceStatus = IPCService.GetInstance().Status;
|
||||
|
||||
try
|
||||
{
|
||||
IPCService.GetInstance().Status = InstanceStatus.Busy;
|
||||
var failed = false;
|
||||
|
||||
if (new ApplyingChangesForm(() =>
|
||||
{
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (!(ProfileRepository.ApplyProfile(profile)))
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}, 3, 30).ShowDialog() !=
|
||||
DialogResult.Cancel)
|
||||
{
|
||||
if (failed)
|
||||
{
|
||||
throw new Exception(Language.Profile_is_invalid_or_not_possible_to_apply);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IPCService.GetInstance().Status = instanceStatus;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user