From 09e2032cf9f04da4d3c6a3e3ef3ec6c44ea1fbdd Mon Sep 17 00:00:00 2001 From: stevealexandre Date: Thu, 8 Sep 2022 02:36:58 +0200 Subject: [PATCH] Add new logic to verify process path and name to handle mid launcher start --- UWPHook/AppManager.cs | 120 +++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/UWPHook/AppManager.cs b/UWPHook/AppManager.cs index cd52f5e..21b4ad2 100644 --- a/UWPHook/AppManager.cs +++ b/UWPHook/AppManager.cs @@ -1,4 +1,5 @@ -using System; +using Serilog; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -7,6 +8,8 @@ using System.Management; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; +using UWPHook.Properties; namespace UWPHook { @@ -17,6 +20,7 @@ namespace UWPHook { private static int runningProcessId; private static bool isLauncherProcess; + private static string executablePath; /// /// Launch a UWP App using a ApplicationActivationManager and sets a internal id to launched proccess id @@ -24,29 +28,29 @@ namespace UWPHook /// The AUMID of the app to launch public static void LaunchUWPApp(string[] args) { - string aumid = args[1]; // We receive the args from Steam, - // 0 is application location, - // 1 is the aumid, the rest are extras - + + + // We receive the args from Steam, + // 0 is application location, + // 1 is the aumid, + // 2 is the executable, the rest are extras + string aumid = args[1]; + executablePath = args[2].Contains("/") ? args[2].Replace('/', '\\') : args[2]; + FileStream debug = File.OpenWrite("debug.log"); + Log.Debug("Arguments => " + String.Join("/", args)); var mgr = new ApplicationActivationManager(); uint processId; - string extra_args = String.Join(" ", args.Skip(2) - .Take(args.Length - 2) + string extra_args = String.Join(" ", args.Skip(3) + .Take(args.Length - 3) .Select(eachElement => eachElement.Clone() ).ToArray()); try { mgr.ActivateApplication(aumid, extra_args, ActivateOptions.None, out processId); - runningProcessId = (int)processId; - - //if this is a launch aided by GameLaunchHelper, deal with child launch later - var possibleLauncher = Process.GetProcessById(runningProcessId); - if (possibleLauncher.ProcessName.Equals("gamelaunchhelper", StringComparison.OrdinalIgnoreCase)) - { - isLauncherProcess = true; - } + runningProcessId = (int) processId; + Log.Debug("Process ID => " + runningProcessId.ToString()); //Bring the launched app to the foreground, this fixes in-home streaming BringProcess(); @@ -63,34 +67,58 @@ namespace UWPHook /// True if the perviously launched app is running, false otherwise public static Boolean IsRunning() { - //If 0, no app was launched most probably - if (runningProcessId != 0) + try { - try + Log.Debug("Checking PID => " + runningProcessId.ToString()); + + // PID 0 means an error during launch for the game + // (Example : Game no more available on gamepass or problem with installation) so instant exit in this case + if (runningProcessId == 0) { - Process.GetProcessById(runningProcessId); - return true; + Log.Debug("PID is 0"); + return false; } - catch + Process.GetProcessById(runningProcessId); + Log.Debug("Process is running"); + return true; + } + catch + { + // Check only at launch if started by a launcher + if (!isLauncherProcess) { - //the process we launched is no longer running. did it spawn any others? - if (isLauncherProcess) + Log.Debug("initial PID is not running anymore, checking other possible process runing before stop"); + bool secondCheck = false; + do { - var tree = GetProcessChildren(); - if (tree.TryGetValue(runningProcessId, out var children)) + // Handle process running by some launcher by checking their executable path and name + var processes = GetProcess(); + foreach (var process in processes) { - //retarget to the first child we find - isLauncherProcess = false; - - var newId = children.First(); - Debug.WriteLine($"Launcher opened child process ({runningProcessId}->{newId}), using new process as target"); - runningProcessId = newId; + string executableFile = executablePath.Contains('\\') ? executablePath.Substring(executablePath.LastIndexOf('\\') + 1) : executablePath; + Log.Debug("Process " + process.Value.Path + " contains " + executablePath + " ? : " + process.Value.Path.Contains(executablePath).ToString()); + Log.Debug("Process " + process.Key + " contains " + executableFile + " ? : " + process.Key.Contains(executableFile).ToString()); + if (process.Value.Path.Contains(executablePath) || process.Key.Contains(executableFile)) + { + int pid = process.Value.Pid; + Log.Debug($"Launcher opened child process ({runningProcessId}->{pid}), using new process as target"); + runningProcessId = pid; + isLauncherProcess = true; + + //bring the "real" launched process + BringProcess(); + return true; + } + } - //bring the "real" launched process - BringProcess(); - return true; + // Handle the last chance if process was not found due to slow running like Farming Simulator 2022 or Halo MCC + secondCheck = !secondCheck; + if (secondCheck) + { + Log.Debug("Process has not been found. Last chance to find it !"); + Thread.Sleep(Settings.Default.Seconds * 5000); } - } + } while (secondCheck); } } @@ -98,26 +126,24 @@ namespace UWPHook } /// - /// Find pid<->parent_pid relationships + /// Find process path with their dedicated pid /// - /// Map of processes to their child IDs. Any process in this object may have already terminated - private static Dictionary> GetProcessChildren() + /// Map of processes to their path and pid. Any process in this object may have already terminated + private static Dictionary GetProcess() { - var result = new Dictionary>(); + var result = new Dictionary(); - using (var searcher = new ManagementObjectSearcher("select processid,parentprocessid from win32_process")) + using (var searcher = new ManagementObjectSearcher("select processid, Name, ExecutablePath from win32_process")) { foreach (var process in searcher.Get()) { + string processName = Convert.ToString(process.Properties["Name"].Value); int processId = Convert.ToInt32(process.Properties["processid"].Value); - int parentId = Convert.ToInt32(process.Properties["parentprocessid"].Value); + string processPath = Convert.ToString(process.Properties["ExecutablePath"].Value); - if (!result.ContainsKey(parentId)) - { - result.Add(parentId, new List()); - } + if (String.IsNullOrWhiteSpace(processName) || result.ContainsKey(processName)) continue; - result[parentId].Add(processId); + result.Add(processName, (processPath, processId)); } } @@ -125,7 +151,7 @@ namespace UWPHook } /// - /// Gets a list of installed UWP Apps on the system, containing each app name + AUMID, separated by '|' + /// Gets a list of installed UWP Apps on the system, containing each app name + AUMID + executable path, separated by '|' /// /// List of installed UWP Apps public static List GetInstalledApps()