Partial fix for process start

CreateProcessWithPriority doesn't always work. Need to troubleshoot why, but at least have a workaround currently.
This commit is contained in:
Terry MacDonald 2021-11-06 21:59:38 +13:00
parent a80349f31a
commit c06ba48923
4 changed files with 97 additions and 34 deletions

View File

@ -560,10 +560,10 @@ namespace DisplayMagician.GameLibraries
args += gameArguments; args += gameArguments;
} }
Process gameProcess = null; Process gameProcess = null;
uint processID = 0; ProcessUtils.PROCESS_INFORMATION processInfo;
if (ProcessUtils.LaunchProcessWithPriority(_gogExe, args, processPriority, out processID)) if (ProcessUtils.CreateProcessWithPriority(_gogExe, args, processPriority, out processInfo))
{ {
gameProcess = Process.GetProcessById((int)processID); gameProcess = Process.GetProcessById(processInfo.dwProcessId);
} }
return gameProcess; return gameProcess;
} }

View File

@ -2,10 +2,11 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace DisplayMagician namespace DisplayMagician
{ {
public class ProcessCreator public class ProcessUtils
{ {
[Flags] [Flags]
@ -94,6 +95,14 @@ namespace DisplayMagician
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation); out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles, PROCESS_CREATION_FLAGS dwCreationFlags,
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute( private static extern bool UpdateProcThreadAttribute(
@ -174,7 +183,7 @@ namespace DisplayMagician
public static bool CreateProcessWithPriority(string exeName, string cmdLine, ProcessPriorityClass priorityClass, out PROCESS_INFORMATION processInfo) public static bool CreateProcessWithPriority(string exeName, string cmdLine, ProcessPriorityClass priorityClass, out PROCESS_INFORMATION processInfo)
{ {
PROCESS_CREATION_FLAGS processFlags = TranslatePriorityClassToFlags(priorityClass) | PROCESS_CREATION_FLAGS.CREATE_SUSPENDED; PROCESS_CREATION_FLAGS processFlags = TranslatePriorityClassToFlags(priorityClass);
bool success = false; bool success = false;
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
var pSec = new SECURITY_ATTRIBUTES(); var pSec = new SECURITY_ATTRIBUTES();
@ -189,16 +198,27 @@ namespace DisplayMagician
} }
catch (Exception ex) catch (Exception ex)
{ {
// This is // This is a problem
}
if (!success)
{
try
{
success = CreateProcess(exeName, cmdLine, IntPtr.Zero, IntPtr.Zero, false, processFlags, IntPtr.Zero, null, ref sInfoEx, out pInfo);
}
catch (Exception ex)
{
// This is a problem too
}
} }
processInfo = pInfo; processInfo = pInfo;
return true; return success;
} }
public static void ResumeProcess(IntPtr threadHandle) public static void ResumeProcess(PROCESS_INFORMATION processInfo)
{ {
ResumeThread(threadHandle); ResumeThread(processInfo.hThread);
} }
public static bool CreateProcessWithParent(int parentProcessId) public static bool CreateProcessWithParent(int parentProcessId)

View File

@ -26,8 +26,8 @@ using System.Resources;
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")] [assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
// Version information // Version information
[assembly: AssemblyVersion("2.1.0.164")] [assembly: AssemblyVersion("2.1.0.174")]
[assembly: AssemblyFileVersion("2.1.0.164")] [assembly: AssemblyFileVersion("2.1.0.174")]
[assembly: NeutralResourcesLanguageAttribute( "en" )] [assembly: NeutralResourcesLanguageAttribute( "en" )]
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]

View File

@ -891,17 +891,42 @@ namespace DisplayMagician
} }
// Start the executable // Start the executable
logger.Info($"ShortcutRepository/RunShortcut: Starting process {processToStart.Executable}"); logger.Info($"ShortcutRepository/RunShortcut: Starting Start Program process {processToStart.Executable}");
Process process = null; Process process = null;
try try
{ {
ProcessUtils.ScanProcesses(); //ProcessUtils.ScanProcesses();
uint processID = 0; ProcessUtils.PROCESS_INFORMATION processInfo;
if (ProcessUtils.LaunchProcessWithPriority(processToStart.Executable, processToStart.Arguments, ProcessUtils.TranslatePriorityToClass(processToStart.ProcessPriority), out processID)) if (ProcessUtils.CreateProcessWithPriority(processToStart.Executable, processToStart.Arguments, ProcessUtils.TranslatePriorityToClass(processToStart.ProcessPriority), out processInfo))
{ {
process = Process.GetProcessById((int)processID); 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) /*if (processToStart.ExecutableArgumentsRequired)
{ {
process = System.Diagnostics.Process.Start(processToStart.Executable, processToStart.Arguments); process = System.Diagnostics.Process.Start(processToStart.Executable, processToStart.Arguments);
@ -922,7 +947,7 @@ namespace DisplayMagician
{ {
logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception setting the start program process priority of start program we started to {shortcutToUse.ProcessPriority.ToString("G")}"); logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception setting the start program process priority of start program we started to {shortcutToUse.ProcessPriority.ToString("G")}");
}*/ }*/
// Record the program we started so we can close it later // Record the program we started so we can close it later
if (processToStart.CloseOnFinish) if (processToStart.CloseOnFinish)
@ -1027,18 +1052,35 @@ namespace DisplayMagician
try try
{ {
Process process = null; Process process = null;
/*if (shortcutToUse.ExecutableArgumentsRequired) ProcessUtils.PROCESS_INFORMATION processInfo;
if (ProcessUtils.CreateProcessWithPriority(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments, ProcessUtils.TranslatePriorityToClass(shortcutToUse.ProcessPriority), out processInfo))
{ {
process = System.Diagnostics.Process.Start(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments); 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 else
{ {
process = System.Diagnostics.Process.Start(shortcutToUse.ExecutableNameAndPath); 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)
uint processID = 0; {
if (ProcessUtils.LaunchProcessWithPriority(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments, ProcessUtils.TranslatePriorityToClass(shortcutToUse.ProcessPriority), out processID)) process = Process.Start(shortcutToUse.ExecutableNameAndPath, shortcutToUse.ExecutableArguments);
{ }
process = Process.GetProcessById((int)processID); else
{
process = Process.Start(shortcutToUse.ExecutableNameAndPath);
}
} }
} }
@ -1811,7 +1853,7 @@ 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"); 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. // Prepare the processInfos we need for finding child processes.
ProcessUtils.ScanProcesses(); //ProcessUtils.ScanProcesses();
// Stop the programs in the reverse order we started them // Stop the programs in the reverse order we started them
foreach (Process processToStop in startProgramsToStop.Reverse<Process>()) foreach (Process processToStop in startProgramsToStop.Reverse<Process>())
@ -1823,11 +1865,11 @@ namespace DisplayMagician
if (!processToStop.HasExited) if (!processToStop.HasExited)
{ {
logger.Debug($"ShortcutRepository/RunShortcut: Stopping process {processToStop.StartInfo.FileName}"); logger.Debug($"ShortcutRepository/RunShortcut: Stopping process {processToStop.StartInfo.FileName}");
if (ProcessUtils.StopProcess(processToStop)) /*if (ProcessUtils.StopProcess(processToStop))
{ {
logger.Debug($"ShortcutRepository/RunShortcut: Successfully stopped process {processToStop.StartInfo.FileName}"); logger.Debug($"ShortcutRepository/RunShortcut: Successfully stopped process {processToStop.StartInfo.FileName}");
stoppedMainProcess = true; stoppedMainProcess = true;
} }*/
} }
} }
catch (Exception ex) catch (Exception ex)
@ -1838,7 +1880,7 @@ namespace DisplayMagician
// Next, check whether it had any other processes it started itself // 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) // (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 // If so, we need to go through and find and close all subprocesses
try /*try
{ {
List<Process> childProcesses = ProcessUtils.FindChildProcesses(processToStop); List<Process> childProcesses = ProcessUtils.FindChildProcesses(processToStop);
if (childProcesses.Count > 0) if (childProcesses.Count > 0)
@ -1863,7 +1905,7 @@ namespace DisplayMagician
catch (Exception ex) catch (Exception ex)
{ {
logger.Error(ex, $"ShortcutRepository/RunShortcut: Exception while checking if processToStop has any child processes"); 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) // 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 // then we try to stop any processes with the same name as the application we started
@ -1879,11 +1921,11 @@ namespace DisplayMagician
// If we have found one or more processes then we should be good to go // If we have found one or more processes then we should be good to go
if (namedProcessesToStop.Count > 0) 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."); /*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) foreach (Process namedProcessToStop in namedProcessesToStop)
{ {
ProcessUtils.StopProcess(namedProcessToStop); ProcessUtils.StopProcess(namedProcessToStop);
} }*/
} }
else else
{ {
@ -2001,7 +2043,8 @@ namespace DisplayMagician
uint processID = 0; uint processID = 0;
try try
{ {
if (ProcessUtils.LaunchProcessWithPriority(stopProg.Executable, stopProg.Arguments, ProcessUtils.TranslatePriorityToClass(stopProg.ProcessPriority), out processID)) ProcessUtils.PROCESS_INFORMATION processInfo;
if (ProcessUtils.CreateProcessWithPriority(stopProg.Executable, stopProg.Arguments, ProcessUtils.TranslatePriorityToClass(stopProg.ProcessPriority), out processInfo))
{ {
logger.Trace($"ShortcutRepository/RunShortcut: Successfully started Stop Program {stopProg.Executable} {stopProg.Arguments}"); logger.Trace($"ShortcutRepository/RunShortcut: Successfully started Stop Program {stopProg.Executable} {stopProg.Arguments}");
} }