mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
First partially working process launching/monitoring update
This commit is contained in:
parent
c06ba48923
commit
10506a6537
@ -556,7 +556,7 @@ namespace DisplayMagician.GameLibraries
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
/*public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
{
|
||||
string address = $@"com.epicgames.launcher://apps/{game.Id}?action=launch&silent=true";
|
||||
if (String.IsNullOrWhiteSpace(gameArguments))
|
||||
@ -566,7 +566,18 @@ namespace DisplayMagician.GameLibraries
|
||||
Process gameProcess = Process.Start(address);
|
||||
gameProcess.PriorityClass = processPriority;
|
||||
return gameProcess;
|
||||
}*/
|
||||
|
||||
public override List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
string address = $@"com.epicgames.launcher://apps/{game.Id}?action=launch&silent=true";
|
||||
if (!String.IsNullOrWhiteSpace(gameArguments))
|
||||
{
|
||||
address += @"/" + gameArguments;
|
||||
}
|
||||
//Process gameProcess = Process.Start(address);
|
||||
List<Process> gameProcesses = ProcessUtils.StartProcess(address, null, processPriority);
|
||||
return gameProcesses;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -552,21 +552,18 @@ namespace DisplayMagician.GameLibraries
|
||||
}
|
||||
|
||||
|
||||
public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
public override List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
string args = $@"/command=runGame /gameId={game.Id} /path=""{game.Directory}""";
|
||||
if (String.IsNullOrWhiteSpace(gameArguments))
|
||||
{
|
||||
args += gameArguments;
|
||||
}
|
||||
Process gameProcess = null;
|
||||
ProcessUtils.PROCESS_INFORMATION processInfo;
|
||||
if (ProcessUtils.CreateProcessWithPriority(_gogExe, args, processPriority, out processInfo))
|
||||
{
|
||||
gameProcess = Process.GetProcessById(processInfo.dwProcessId);
|
||||
}
|
||||
return gameProcess;
|
||||
List<Process> gameProcesses = ProcessUtils.StartProcess(_gogExe, args, processPriority);
|
||||
return gameProcesses;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ namespace DisplayMagician.GameLibraries
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
public virtual List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -725,7 +725,7 @@ namespace DisplayMagician.GameLibraries
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
/*public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
{
|
||||
string address = $"origin2://game/launch?offerIds={game.Id}";
|
||||
if (String.IsNullOrWhiteSpace(gameArguments))
|
||||
@ -735,6 +735,17 @@ namespace DisplayMagician.GameLibraries
|
||||
Process gameProcess = Process.Start(address);
|
||||
gameProcess.PriorityClass = processPriority;
|
||||
return gameProcess;
|
||||
}*/
|
||||
public override List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
string address = $"origin2://game/launch?offerIds={game.Id}";
|
||||
if (!String.IsNullOrWhiteSpace(gameArguments))
|
||||
{
|
||||
address += @"/" + gameArguments;
|
||||
}
|
||||
//Process gameProcess = Process.Start(address);
|
||||
List<Process> gameProcesses = ProcessUtils.StartProcess(address, null, processPriority);
|
||||
return gameProcesses;
|
||||
}
|
||||
|
||||
|
||||
|
@ -808,16 +808,16 @@ namespace DisplayMagician.GameLibraries
|
||||
}
|
||||
|
||||
|
||||
public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
public override List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
string address = $@"steam://rungameid/{game.Id}";
|
||||
if (!String.IsNullOrWhiteSpace(gameArguments))
|
||||
{
|
||||
address += @"//" + gameArguments;
|
||||
}
|
||||
Process gameProcess = Process.Start(address);
|
||||
gameProcess.PriorityClass = processPriority;
|
||||
return gameProcess;
|
||||
//Process gameProcess = Process.Start(address);
|
||||
List<Process> gameProcesses = ProcessUtils.StartProcess(address,null,processPriority);
|
||||
return gameProcesses;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -887,7 +887,7 @@ namespace DisplayMagician.GameLibraries
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
/*public override Process StartGame(Game game, string gameArguments = "", ProcessPriorityClass processPriority = ProcessPriorityClass.Normal)
|
||||
{
|
||||
string address = $@"uplay://launch/{game.Id}";
|
||||
if (String.IsNullOrWhiteSpace(gameArguments))
|
||||
@ -902,6 +902,21 @@ namespace DisplayMagician.GameLibraries
|
||||
gameProcess.PriorityClass = processPriority;
|
||||
return gameProcess;
|
||||
|
||||
}*/
|
||||
|
||||
public override List<Process> StartGame(Game game, string gameArguments = "", ProcessPriority processPriority = ProcessPriority.Normal)
|
||||
{
|
||||
string address = $@"uplay://launch/{game.Id}";
|
||||
if (String.IsNullOrWhiteSpace(gameArguments))
|
||||
{
|
||||
address += @"/" + gameArguments;
|
||||
}
|
||||
else
|
||||
{
|
||||
address += "/0";
|
||||
}
|
||||
List<Process> gameProcesses = ProcessUtils.StartProcess(address, null, processPriority);
|
||||
return gameProcesses;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DisplayMagician
|
||||
@ -9,8 +13,10 @@ namespace DisplayMagician
|
||||
public class ProcessUtils
|
||||
{
|
||||
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Flags]
|
||||
public enum PROCESS_CREATION_FLAGS : uint
|
||||
public enum PROCESS_CREATION_FLAGS : UInt32
|
||||
{
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
@ -181,6 +187,135 @@ namespace DisplayMagician
|
||||
return wantedPriorityClass;
|
||||
}
|
||||
|
||||
public static List<Process> StartProcess(string executable, string arguments, ProcessPriority processPriority, int startTimeout = 1)
|
||||
{
|
||||
List<Process> runningProcesses = new List<Process>();
|
||||
Process process = null;
|
||||
PROCESS_INFORMATION processInfo;
|
||||
try
|
||||
{
|
||||
if (CreateProcessWithPriority(executable, arguments, ProcessUtils.TranslatePriorityToClass(processPriority), out processInfo))
|
||||
{
|
||||
if (processInfo.dwProcessId > 0)
|
||||
{
|
||||
process = Process.GetProcessById(processInfo.dwProcessId);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"ProcessUtils/StartProcess: CreateProcessWithPriority returned a process with PID 0 when trying to start process {executable}. This indicates that the process was not started, so we'll try it a different way.");
|
||||
// Start the process using built in process library
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = executable;
|
||||
psi.Arguments = arguments;
|
||||
psi.WorkingDirectory = Path.GetDirectoryName(executable);
|
||||
process = Process.Start(psi);
|
||||
processInfo.hProcess = process.Handle;
|
||||
processInfo.dwProcessId = process.Id;
|
||||
processInfo.dwThreadId = process.Threads[0].Id;
|
||||
if (!process.HasExited)
|
||||
{
|
||||
// Change priority if we can (not always possible in this mode :(
|
||||
try
|
||||
{
|
||||
// If this process is a protected process, then this will fail!
|
||||
process.PriorityClass = ProcessUtils.TranslatePriorityToClass(processPriority);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We would need need higher rights for this processto set the priority
|
||||
// https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
||||
// At this stage I am not writing this, as it is a lot of work for a niche issue.
|
||||
}
|
||||
runningProcesses.Add(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start the process using built in process library
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = executable;
|
||||
psi.Arguments = arguments;
|
||||
psi.WorkingDirectory = Path.GetDirectoryName(executable);
|
||||
process = Process.Start(psi);
|
||||
processInfo.hProcess = process.Handle;
|
||||
processInfo.dwProcessId = process.Id;
|
||||
if (!process.HasExited)
|
||||
{
|
||||
processInfo.dwThreadId = process.Threads[0].Id;
|
||||
// Change priority if we can (not always possible in this mode :(
|
||||
try
|
||||
{
|
||||
// If this process is a protected process, then this will fail!
|
||||
process.PriorityClass = ProcessUtils.TranslatePriorityToClass(processPriority);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
// We would need need higher rights for this processto set the priority
|
||||
// https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
||||
// At this stage I am not writing this, as it is a lot of work for a niche issue.
|
||||
}
|
||||
runningProcesses.Add(process);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
// Start the process using built in process library
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = executable;
|
||||
psi.Arguments = arguments;
|
||||
psi.WorkingDirectory = Path.GetDirectoryName(executable);
|
||||
process = Process.Start(psi);
|
||||
processInfo.hProcess = process.Handle;
|
||||
processInfo.dwProcessId = process.Id;
|
||||
processInfo.dwThreadId = process.Threads[0].Id;
|
||||
//pInfo.dwThreadId = process.Threads[0].Id;
|
||||
// Change priority
|
||||
if (!process.HasExited)
|
||||
{
|
||||
runningProcesses.Add(process);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Check the launched exe hasn't exited within 2 secs
|
||||
for (int secs = 0; secs <= (startTimeout * 1000); secs += 500)
|
||||
{
|
||||
// If we have no more processes left then we're done!
|
||||
if (process.HasExited)
|
||||
{
|
||||
logger.Trace($"ProcessUtils/StartProcess: {executable} has exited early! It's likely to be a launcher! Trying to detect it's children.");
|
||||
// As the original process has left the building, we'll overwrite it with the children processes
|
||||
runningProcesses = GetChildProcesses(process);
|
||||
break;
|
||||
}
|
||||
// Send a message to windows so that it doesn't think
|
||||
// we're locked and try to kill us
|
||||
System.Threading.Thread.CurrentThread.Join(0);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
return runningProcesses;
|
||||
}
|
||||
|
||||
public static List<Process> GetChildProcesses(Process process)
|
||||
{
|
||||
List<Process> children = new List<Process>();
|
||||
ManagementObjectSearcher mos = new ManagementObjectSearcher($"Select * From Win32_Process Where ParentProcessID={process.Id}");
|
||||
foreach (ManagementObject mo in mos.Get())
|
||||
{
|
||||
children.Add(Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
public static bool CreateProcessWithPriority(string exeName, string cmdLine, ProcessPriorityClass priorityClass, out PROCESS_INFORMATION processInfo)
|
||||
{
|
||||
PROCESS_CREATION_FLAGS processFlags = TranslatePriorityClassToFlags(priorityClass);
|
||||
@ -296,6 +431,135 @@ namespace DisplayMagician
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessExited(Process process)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process processToTest = Process.GetProcessById(process.Id);
|
||||
if (processToTest.HasExited)
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited: {process.Id} has exited and is not running. This means the process has finished!");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited: {process.Id} is still running as is has not exited yet.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited: {process.Id} is not running, and the process ID has expired. This means the process has finished!");
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
logger.Warn($"ProcessUtils/ProcessExited: {process.Id} was not started by this process object. This likely means the process has finished!");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited: Exception when checking if {process.Id} is still running, so assuming the process has finished!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessExited(List<Process> processes)
|
||||
{
|
||||
int processClosedCount = 0;
|
||||
foreach (Process p in processes)
|
||||
{
|
||||
if (ProcessExited(p))
|
||||
{
|
||||
processClosedCount++;
|
||||
}
|
||||
}
|
||||
if (processClosedCount == processes.Count)
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited2: All processes being monitored have exited, so no processes still running!");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Trace($"ProcessUtils/ProcessExited2: {processClosedCount} processes out of {processes.Count} processes have exited. At least one process is still running!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool StopProcess(Process processToStop)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Stop the process
|
||||
processToStop.CloseMainWindow();
|
||||
if (!processToStop.WaitForExit(5000))
|
||||
{
|
||||
logger.Trace($"ProcessUtils/StopProcess: Process {processToStop.StartInfo.FileName} wouldn't stop cleanly. Forcing program close.");
|
||||
processToStop.Kill();
|
||||
if (!processToStop.WaitForExit(5000))
|
||||
{
|
||||
logger.Error($"ProcessUtils/StopProcess: Process {processToStop.StartInfo.FileName} couldn't be killed! It seems like something is actively preventing us from stopping the process");
|
||||
return false;
|
||||
}
|
||||
logger.Trace($"ProcessUtils/StopProcess: Process {processToStop.StartInfo.FileName} was successfully killed.");
|
||||
}
|
||||
processToStop.Close();
|
||||
return true;
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
{
|
||||
logger.Warn(ex, $"ProcessUtils/StopProcess: Win32Exception! Couldn't access the wait status for a named process we're trying to stop. So now just killing the process.");
|
||||
processToStop.Kill();
|
||||
if (!processToStop.WaitForExit(5000))
|
||||
{
|
||||
logger.Error($"ProcessUtils/StopProcess: Win32Exception! Process {processToStop.StartInfo.FileName} couldn't be killed! It seems like something is actively preventing us from stopping the process");
|
||||
return false;
|
||||
}
|
||||
logger.Trace($"ProcessUtils/StopProcess: Win32Exception! Process {processToStop.StartInfo.FileName} was successfully killed.");
|
||||
processToStop.Close();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
logger.Error(ex, $"ProcessUtils/StopProcess: Couldn't kill the named process as the process appears to have closed already.");
|
||||
}
|
||||
catch (SystemException ex)
|
||||
{
|
||||
logger.Error(ex, $"ProcessUtils/StopProcess: Couldn't WaitForExit the named process as there is no process associated with the Process object (or cannot get the ID from the named process handle).");
|
||||
}
|
||||
|
||||
catch (AggregateException ae)
|
||||
{
|
||||
logger.Error(ae, $"ProcessUtils/StopProcess: Got an AggregateException.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool StopProcess(List<Process> processes)
|
||||
{
|
||||
// Stop the programs in the reverse order we started them
|
||||
foreach (Process processToStop in processes)
|
||||
{
|
||||
// Stop the process if it hasn't stopped already
|
||||
try
|
||||
{
|
||||
if (!processToStop.HasExited)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Stopping process {processToStop.StartInfo.FileName}");
|
||||
if (ProcessUtils.StopProcess(processToStop))
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Successfully stopped process {processToStop.StartInfo.FileName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception while checking if processToStop has already exited");
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,8 @@ using System.Resources;
|
||||
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
|
||||
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("2.1.0.174")]
|
||||
[assembly: AssemblyFileVersion("2.1.0.174")]
|
||||
[assembly: AssemblyVersion("2.1.0.179")]
|
||||
[assembly: AssemblyFileVersion("2.1.0.179")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en" )]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
|
@ -892,72 +892,27 @@ namespace DisplayMagician
|
||||
|
||||
// Start the executable
|
||||
logger.Info($"ShortcutRepository/RunShortcut: Starting Start Program process {processToStart.Executable}");
|
||||
Process process = null;
|
||||
//Process process = null;
|
||||
List<Process> processesCreated = new List<Process>();
|
||||
try
|
||||
{
|
||||
//ProcessUtils.ScanProcesses();
|
||||
ProcessUtils.PROCESS_INFORMATION processInfo;
|
||||
if (ProcessUtils.CreateProcessWithPriority(processToStart.Executable, processToStart.Arguments, ProcessUtils.TranslatePriorityToClass(processToStart.ProcessPriority), out processInfo))
|
||||
{
|
||||
if (processInfo.dwProcessId > 0)
|
||||
{
|
||||
process = Process.GetProcessById(processInfo.dwProcessId);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"ShortcutRepository/RunShortcut: CreateProcessWithPriority returned a process with PID 0 when trying to start process {processToStart.Executable}. This indicates that the process was not started.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = processToStart.Executable;
|
||||
psi.Arguments = processToStart.Arguments;
|
||||
psi.WorkingDirectory = Path.GetDirectoryName(processToStart.Executable);
|
||||
process = Process.Start(psi);
|
||||
processInfo.hProcess = process.Handle;
|
||||
processInfo.dwProcessId = process.Id;
|
||||
processInfo.dwThreadId = process.Threads[0].Id;
|
||||
//pInfo.dwThreadId = process.Threads[0].Id;
|
||||
Task.Delay(500);
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.PriorityClass = ProcessUtils.TranslatePriorityToClass(processToStart.ProcessPriority);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*if (processToStart.ExecutableArgumentsRequired)
|
||||
{
|
||||
process = System.Diagnostics.Process.Start(processToStart.Executable, processToStart.Arguments);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
process = System.Diagnostics.Process.Start(processToStart.Executable);
|
||||
}*/
|
||||
|
||||
/*try
|
||||
{
|
||||
// Attempt to set the process priority to whatever the user wanted
|
||||
logger.Trace($"ShortcutRepository/RunShortcut: Setting the start program process priority of start program we started to {shortcutToUse.ProcessPriority.ToString("G")}");
|
||||
process.PriorityClass = TranslatePriorityClass(processToStart.ProcessPriority);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception setting the start program process priority of start program we started to {shortcutToUse.ProcessPriority.ToString("G")}");
|
||||
}*/
|
||||
|
||||
processesCreated = ProcessUtils.StartProcess(processToStart.Executable, processToStart.Arguments, processToStart.ProcessPriority);
|
||||
|
||||
// Record the program we started so we can close it later
|
||||
if (processToStart.CloseOnFinish)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: We need to stop {processToStart.Executable} after the main game or executable is closed.");
|
||||
startProgramsToStop.Add(process);
|
||||
foreach (Process p in processesCreated)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: We need to stop {p.StartInfo.FileName} after the main game or executable is closed.");
|
||||
}
|
||||
startProgramsToStop.AddRange(processesCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: No need to stop {processToStart.Executable} after the main game or executable is closed, so we'll just leave it running");
|
||||
foreach (Process p in processesCreated)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: No need to stop {p.StartInfo.FileName} after the main game or executable is closed, so we'll just leave it running");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
@ -1043,44 +998,65 @@ namespace DisplayMagician
|
||||
}
|
||||
|
||||
|
||||
// Now start the main game, and wait if we have to
|
||||
// Now start the main game/exe, and wait if we have to
|
||||
if (shortcutToUse.Category.Equals(ShortcutCategory.Application))
|
||||
{
|
||||
logger.Info($"ShortcutRepository/RunShortcut: Starting the main executable that we wanted to run, and that we're going to monitor and watch");
|
||||
// Start the executable
|
||||
// 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
|
||||
string notificationText = $"DisplayMagician: Running {shortcutToUse.ExecutableNameAndPath}...";
|
||||
if (notificationText.Length >= 64)
|
||||
{
|
||||
string thingToRun = shortcutToUse.ExecutableNameAndPath.Substring(0, 34);
|
||||
notifyIcon.Text = $"DisplayMagician: Running {thingToRun}...";
|
||||
}
|
||||
Application.DoEvents();
|
||||
|
||||
string processToMonitorName;
|
||||
if (shortcutToUse.ProcessNameToMonitorUsesExecutable)
|
||||
{
|
||||
processToMonitorName = shortcutToUse.ExecutableNameAndPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
processToMonitorName = shortcutToUse.DifferentExecutableToMonitor;
|
||||
}
|
||||
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Creating the Windows Toast to notify the user we're going to wait for the executable {shortcutToUse.ExecutableNameAndPath} to close.");
|
||||
// Now we want to tell the user we're running an application!
|
||||
// Construct the Windows toast content
|
||||
ToastContentBuilder tcBuilder = new ToastContentBuilder()
|
||||
.AddToastActivationInfo("notify=runningApplication", ToastActivationType.Foreground)
|
||||
.AddText($"Running {shortcutToUse.ExecutableNameAndPath}", hintMaxLines: 1)
|
||||
.AddText($"Waiting for all {processToMonitorName } processes to exit...")
|
||||
.AddAudio(new Uri("ms-winsoundevent:Notification.Default"), false, true);
|
||||
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
|
||||
ToastContent toastContent = tcBuilder.Content;
|
||||
// Make sure to use Windows.Data.Xml.Dom
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(toastContent.GetContent());
|
||||
// And create the toast notification
|
||||
var toast = new ToastNotification(doc);
|
||||
toast.SuppressPopup = false;
|
||||
// Remove any other Notifications from us
|
||||
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
|
||||
// And then show this notification
|
||||
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
|
||||
|
||||
|
||||
logger.Info($"ShortcutRepository/RunShortcut: Starting the main executable that we wanted to run, and that we're going to monitor and watch");
|
||||
// Start the main executable
|
||||
List<Process> processesCreated = new List<Process>();
|
||||
try
|
||||
{
|
||||
Process process = null;
|
||||
ProcessUtils.PROCESS_INFORMATION processInfo;
|
||||
if (ProcessUtils.CreateProcessWithPriority(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments, ProcessUtils.TranslatePriorityToClass(shortcutToUse.ProcessPriority), out processInfo))
|
||||
processesCreated = ProcessUtils.StartProcess(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments, shortcutToUse.ProcessPriority);
|
||||
|
||||
// Record the program we started so we can close it later
|
||||
foreach (Process p in processesCreated)
|
||||
{
|
||||
process = Process.GetProcessById(processInfo.dwProcessId);
|
||||
Task.Delay(500);
|
||||
if (process != null)
|
||||
{
|
||||
if (process.HasExited)
|
||||
{
|
||||
// Then we need to find what processes are running now with a parent of processInfo.process
|
||||
logger.Error($"ShortcutRepository/RunShortcut: Main executable process {shortcutToUse.ExecutableNameAndPath} has exited after a short delay. It is likely to be a launcher process. We're going to look for it's children.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"ShortcutRepository/RunShortcut: Main executable process {shortcutToUse.ExecutableNameAndPath} didn't start for some reason. Process still = null.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error($"ShortcutRepository/RunShortcut: CreateProcessWithPriority couldn't create Main executable process {shortcutToUse.ExecutableNameAndPath}. Going to try to start it the old way without priority.");
|
||||
if (shortcutToUse.ExecutableArgumentsRequired)
|
||||
{
|
||||
process = Process.Start(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
process = Process.Start(shortcutToUse.ExecutableNameAndPath);
|
||||
}
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: {p.StartInfo.FileName} was launched when we started the main application {shortcutToUse.ExecutableNameAndPath}.");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1101,110 +1077,44 @@ namespace DisplayMagician
|
||||
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception starting main executable process {shortcutToUse.ExecutableNameAndPath}. Method call is invalid for the current state.");
|
||||
}
|
||||
|
||||
// Figure out what we want to look for
|
||||
string processNameToLookFor;
|
||||
// Wait an extra few seconds to give the application time to settle down
|
||||
//Thread.Sleep(2000);
|
||||
|
||||
// Now we need to decide what we are monitoring. If the user has supplied an alternative process to monitor, then we monitor that instead!
|
||||
bool foundSomethingToMonitor = false;
|
||||
List<Process> processesToMonitor = new List<Process>();
|
||||
if (shortcutToUse.ProcessNameToMonitorUsesExecutable)
|
||||
{
|
||||
// If we are monitoring the same executable we started, then lets do get that name ready
|
||||
processNameToLookFor = System.IO.Path.GetFileNameWithoutExtension(shortcutToUse.ExecutableNameAndPath);
|
||||
processesToMonitor = processesCreated;
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: {processesToMonitor.Count} '{processToMonitorName}' created processes to monitor are running");
|
||||
foundSomethingToMonitor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are monitoring a different executable, then lets do get that name ready instead
|
||||
processNameToLookFor = System.IO.Path.GetFileNameWithoutExtension(shortcutToUse.DifferentExecutableToMonitor);
|
||||
}
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Looking for processes with the name {processNameToLookFor} so that we can monitor them and know when they are closed.");
|
||||
|
||||
// Now look for the thing we're supposed to monitor
|
||||
// and wait until it starts up
|
||||
List<Process> processesToMonitor = new List<Process>();
|
||||
for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500)
|
||||
{
|
||||
// Look for the processes with the ProcessName we sorted out earlier
|
||||
processesToMonitor = Process.GetProcessesByName(processNameToLookFor).ToList();
|
||||
|
||||
// If we have found one or more processes then we should be good to go
|
||||
// so let's break
|
||||
if (processesToMonitor.Count > 0)
|
||||
// We use the a user supplied executable as the thing we're monitoring instead!
|
||||
try
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Found {processesToMonitor.Count} '{processNameToLookFor}' processes to monitor");
|
||||
|
||||
try
|
||||
{
|
||||
foreach (Process monitoredProcess in processesToMonitor)
|
||||
{
|
||||
logger.Trace($"ShortcutRepository/RunShortcut: Setting priority of monitored executable process {processNameToLookFor} to {shortcutToUse.ProcessPriority.ToString("G")}");
|
||||
monitoredProcess.PriorityClass = TranslatePriorityClassToClass(shortcutToUse.ProcessPriority);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception Setting priority of monitored executable process {processNameToLookFor} to {shortcutToUse.ProcessPriority.ToString("G")}");
|
||||
}
|
||||
|
||||
break;
|
||||
processesToMonitor.AddRange(Process.GetProcessesByName(shortcutToUse.DifferentExecutableToMonitor));
|
||||
logger.Trace($"ShortcutRepository/RunShortcut: {processesToMonitor.Count} '{shortcutToUse.DifferentExecutableToMonitor}' user specified processes to monitor are running");
|
||||
foundSomethingToMonitor = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"ShortcutRepository/RunShortcut: Exception while trying to find the user supplied executable to monitor: {shortcutToUse.DifferentExecutableToMonitor}.");
|
||||
foundSomethingToMonitor = false;
|
||||
}
|
||||
|
||||
// Let's wait a little while if we couldn't find
|
||||
// any processes yet
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
// make sure we have things to monitor and alert if not
|
||||
if (processesToMonitor.Count == 0)
|
||||
{
|
||||
logger.Error($"ShortcutRepository/RunShortcut: No '{processNameToLookFor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout");
|
||||
}
|
||||
|
||||
// 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
|
||||
string notificationText = $"DisplayMagician: Running {shortcutToUse.ExecutableNameAndPath}...";
|
||||
if (notificationText.Length >= 64)
|
||||
{
|
||||
string thingToRun = shortcutToUse.ExecutableNameAndPath.Substring(0, 34);
|
||||
notifyIcon.Text = $"DisplayMagician: Running {thingToRun}...";
|
||||
}
|
||||
Application.DoEvents();
|
||||
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Creating the Windows Toast to notify the user we're going to wait for the executable {shortcutToUse.ExecutableNameAndPath} to close.");
|
||||
// Now we want to tell the user we're running an application!
|
||||
// Construct the Windows toast content
|
||||
ToastContentBuilder tcBuilder = new ToastContentBuilder()
|
||||
.AddToastActivationInfo("notify=runningApplication", ToastActivationType.Foreground)
|
||||
.AddText($"Running {processNameToLookFor}", hintMaxLines: 1)
|
||||
.AddText($"Waiting for all {processNameToLookFor} windows to exit...")
|
||||
.AddAudio(new Uri("ms-winsoundevent:Notification.Default"),false,true);
|
||||
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
|
||||
ToastContent toastContent = tcBuilder.Content;
|
||||
// Make sure to use Windows.Data.Xml.Dom
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(toastContent.GetContent());
|
||||
// And create the toast notification
|
||||
var toast = new ToastNotification(doc);
|
||||
toast.SuppressPopup = false;
|
||||
// Remove any other Notifications from us
|
||||
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
|
||||
// And then show this notification
|
||||
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
|
||||
|
||||
// Wait an extra few seconds to give the application time to settle down
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// if we have things to monitor, then we should start to wait for them
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Waiting for application {processNameToLookFor} to exit.");
|
||||
if (processesToMonitor.Count > 0)
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Waiting for application {shortcutToUse.ExecutableNameAndPath} to exit.");
|
||||
if (foundSomethingToMonitor && processesToMonitor.Count > 0)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: {processesToMonitor.Count} '{processNameToLookFor}' processes are still running");
|
||||
while (true)
|
||||
{
|
||||
processesToMonitor = Process.GetProcessesByName(processNameToLookFor).ToList();
|
||||
|
||||
// If we have no more processes left then we're done!
|
||||
if (processesToMonitor.Count == 0)
|
||||
if (ProcessUtils.ProcessExited(processesToMonitor))
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: No more '{processNameToLookFor}' processes are still running");
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: No more processes to monitor are still running. It, and all it's child processes have exited!");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1214,15 +1124,14 @@ namespace DisplayMagician
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
logger.Info($"ShortcutRepository/RunShortcut: Executable {processNameToLookFor} has exited.");
|
||||
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Creating a Windows Toast to notify the user that the executable {shortcutToUse.ExecutableNameAndPath} has closed.");
|
||||
// Tell the user that the application has closed
|
||||
// Construct the toast content
|
||||
tcBuilder = new ToastContentBuilder()
|
||||
.AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground)
|
||||
.AddText($"{processNameToLookFor} was closed", hintMaxLines: 1)
|
||||
.AddText($"All {processNameToLookFor} processes were shutdown and changes were reverted.")
|
||||
.AddText($"{shortcutToUse.ExecutableNameAndPath} was closed", hintMaxLines: 1)
|
||||
.AddText($"All {processToMonitorName} processes were shutdown and changes were reverted.")
|
||||
.AddAudio(new Uri("ms-winsoundevent:Notification.Default"), false, true);
|
||||
toastContent = tcBuilder.Content;
|
||||
// Make sure to use Windows.Data.Xml.Dom
|
||||
@ -1279,6 +1188,25 @@ namespace DisplayMagician
|
||||
if (gameToRun != null)
|
||||
{
|
||||
|
||||
string processToMonitorName;
|
||||
if (shortcutToUse.MonitorDifferentGameExe)
|
||||
{
|
||||
processToMonitorName = shortcutToUse.DifferentGameExeToMonitor;
|
||||
}
|
||||
else
|
||||
{
|
||||
processToMonitorName = gameToRun.ExePath;
|
||||
}
|
||||
|
||||
// Add a status notification icon in the status area
|
||||
string notificationText = $"DisplayMagician: Running {gameLibraryToUse.GameLibraryName}...";
|
||||
if (notificationText.Length >= 64)
|
||||
{
|
||||
string thingToRun = gameLibraryToUse.GameLibraryName.Substring(0, 34);
|
||||
notifyIcon.Text = $"DisplayMagician: Running {thingToRun}...";
|
||||
}
|
||||
Application.DoEvents();
|
||||
|
||||
// Now we want to tell the user we're start a game
|
||||
// Construct the Windows toast content
|
||||
ToastContentBuilder tcBuilder = new ToastContentBuilder()
|
||||
@ -1298,10 +1226,8 @@ namespace DisplayMagician
|
||||
// And then show this notification
|
||||
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
|
||||
|
||||
Process gameProcess;
|
||||
//string gameRunCmd = gameLibraryToUse.GetRunCmd(gameToRun, shortcutToUse.GameArguments);
|
||||
//gameProcess = Process.Start(gameRunCmd);
|
||||
gameProcess = gameLibraryToUse.StartGame(gameToRun, shortcutToUse.GameArguments, ProcessUtils.TranslatePriorityToClass(shortcutToUse.ProcessPriority));
|
||||
List<Process> gameProcesses;
|
||||
gameProcesses = gameLibraryToUse.StartGame(gameToRun, shortcutToUse.GameArguments, shortcutToUse.ProcessPriority);
|
||||
|
||||
// Delay 500ms
|
||||
Thread.Sleep(500);
|
||||
@ -1416,7 +1342,9 @@ namespace DisplayMagician
|
||||
|
||||
}
|
||||
|
||||
string notificationText = $"DisplayMagician: Running {gameToRun.Name}...";
|
||||
// Now we actually start looking for and monitoring the game!
|
||||
|
||||
notificationText = $"DisplayMagician: Running {gameToRun.Name}...";
|
||||
if (notificationText.Length >= 64)
|
||||
{
|
||||
string thingToRun = gameToRun.Name.Substring(0, 34);
|
||||
@ -1457,7 +1385,6 @@ namespace DisplayMagician
|
||||
{
|
||||
logger.Warn(ex, $"ShortcutRepository/RunShortcut: Setting priority of alternative game monitored process {altGameProcessToMonitor} to {shortcutToUse.ProcessPriority.ToString("G")}");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1852,96 +1779,8 @@ namespace DisplayMagician
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: We started {startProgramsToStart.Count} programs before the main executable or game, and now we want to stop {startProgramsToStop.Count } of them");
|
||||
|
||||
// Prepare the processInfos we need for finding child processes.
|
||||
//ProcessUtils.ScanProcesses();
|
||||
|
||||
// Stop the programs in the reverse order we started them
|
||||
foreach (Process processToStop in startProgramsToStop.Reverse<Process>())
|
||||
{
|
||||
bool stoppedMainProcess = false;
|
||||
// Stop the process if it hasn't stopped already
|
||||
try
|
||||
{
|
||||
if (!processToStop.HasExited)
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Stopping process {processToStop.StartInfo.FileName}");
|
||||
/*if (ProcessUtils.StopProcess(processToStop))
|
||||
{
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Successfully stopped process {processToStop.StartInfo.FileName}");
|
||||
stoppedMainProcess = true;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception while checking if processToStop has already exited");
|
||||
}
|
||||
|
||||
// Next, check whether it had any other processes it started itself
|
||||
// (copes with loader processes that perform the initial start, then run the main exe)
|
||||
// If so, we need to go through and find and close all subprocesses
|
||||
/*try
|
||||
{
|
||||
List<Process> childProcesses = ProcessUtils.FindChildProcesses(processToStop);
|
||||
if (childProcesses.Count > 0)
|
||||
{
|
||||
foreach (Process childProcessToStop in childProcesses)
|
||||
{
|
||||
if (processToStop.HasExited)
|
||||
{
|
||||
// if there were no child processes, and the only process has already exited (e.g. the user exited it themselves)
|
||||
// then stop trying to stop the process, and instead log the fact it already stopped.
|
||||
Console.WriteLine($"Stopping child process {childProcessToStop.StartInfo.FileName} but was already stopped by user or another process.");
|
||||
logger.Warn($"ShortcutRepository/RunShortcut: Stopping child process {childProcessToStop.StartInfo.FileName} but was already stopped by user or another process.");
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Stopping child process {childProcessToStop.StartInfo.FileName} of parent process {processToStop.StartInfo.FileName}");
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Stopping child process {childProcessToStop.StartInfo.FileName} of parent process {processToStop.StartInfo.FileName}");
|
||||
ProcessUtils.StopProcess(childProcessToStop);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception while checking if processToStop has any child processes");
|
||||
}*/
|
||||
|
||||
// if the only main process has already exited (e.g. the user exited it themselves)
|
||||
// then we try to stop any processes with the same name as the application we started
|
||||
// Look for the processes with the ProcessName we sorted out earlier
|
||||
// Basically, if we haven't stopped all the children processes, then this is the last gasp
|
||||
try
|
||||
{
|
||||
if (!stoppedMainProcess)
|
||||
{
|
||||
string processName = Path.GetFileNameWithoutExtension(processToStop.StartInfo.FileName);
|
||||
List<Process> namedProcessesToStop = Process.GetProcessesByName(processName).ToList();
|
||||
|
||||
// If we have found one or more processes then we should be good to go
|
||||
if (namedProcessesToStop.Count > 0)
|
||||
{
|
||||
/*logger.Warn($"ShortcutRepository/RunShortcut: We couldn't find any children processes so we've looked for named processes with the name '{processToStop.StartInfo.FileName}' and we found {namedProcessesToStop.Count}. Closing them.");
|
||||
foreach (Process namedProcessToStop in namedProcessesToStop)
|
||||
{
|
||||
ProcessUtils.StopProcess(namedProcessToStop);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// then give up trying to stop the process, and instead log the fact it already stopped.
|
||||
Console.WriteLine($"Stopping only process {processToStop.StartInfo.FileName} but was already stopped by user or another process.");
|
||||
logger.Debug($"ShortcutRepository/RunShortcut: Stopping only process {processToStop.StartInfo.FileName} but was already stopped by user or another process.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception while looking for other processes similar to processToStop for us to stop.");
|
||||
}
|
||||
|
||||
}
|
||||
// Shutdown the processes
|
||||
ProcessUtils.StopProcess(startProgramsToStop);
|
||||
}
|
||||
|
||||
// Change Audio Device back (if one specified)
|
||||
|
Loading…
Reference in New Issue
Block a user