Add new logic to verify process path and name to handle mid launcher start

pull/96/head
stevealexandre 2 years ago
parent 266dab93b9
commit 09e2032cf9

@ -1,4 +1,5 @@
using System; using Serilog;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -7,6 +8,8 @@ using System.Management;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using UWPHook.Properties;
namespace UWPHook namespace UWPHook
{ {
@ -17,6 +20,7 @@ namespace UWPHook
{ {
private static int runningProcessId; private static int runningProcessId;
private static bool isLauncherProcess; private static bool isLauncherProcess;
private static string executablePath;
/// <summary> /// <summary>
/// Launch a UWP App using a ApplicationActivationManager and sets a internal id to launched proccess id /// Launch a UWP App using a ApplicationActivationManager and sets a internal id to launched proccess id
@ -24,29 +28,29 @@ namespace UWPHook
/// <param name="aumid">The AUMID of the app to launch</param> /// <param name="aumid">The AUMID of the app to launch</param>
public static void LaunchUWPApp(string[] args) 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(); var mgr = new ApplicationActivationManager();
uint processId; uint processId;
string extra_args = String.Join(" ", args.Skip(2) string extra_args = String.Join(" ", args.Skip(3)
.Take(args.Length - 2) .Take(args.Length - 3)
.Select(eachElement => eachElement.Clone() .Select(eachElement => eachElement.Clone()
).ToArray()); ).ToArray());
try try
{ {
mgr.ActivateApplication(aumid, extra_args, ActivateOptions.None, out processId); mgr.ActivateApplication(aumid, extra_args, ActivateOptions.None, out processId);
runningProcessId = (int)processId; runningProcessId = (int) processId;
Log.Debug("Process ID => " + runningProcessId.ToString());
//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;
}
//Bring the launched app to the foreground, this fixes in-home streaming //Bring the launched app to the foreground, this fixes in-home streaming
BringProcess(); BringProcess();
@ -63,34 +67,58 @@ namespace UWPHook
/// <returns>True if the perviously launched app is running, false otherwise</returns> /// <returns>True if the perviously launched app is running, false otherwise</returns>
public static Boolean IsRunning() public static Boolean IsRunning()
{ {
//If 0, no app was launched most probably try
if (runningProcessId != 0)
{ {
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); Log.Debug("PID is 0");
return true; 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? Log.Debug("initial PID is not running anymore, checking other possible process runing before stop");
if (isLauncherProcess) bool secondCheck = false;
do
{ {
var tree = GetProcessChildren(); // Handle process running by some launcher by checking their executable path and name
if (tree.TryGetValue(runningProcessId, out var children)) var processes = GetProcess();
foreach (var process in processes)
{ {
//retarget to the first child we find string executableFile = executablePath.Contains('\\') ? executablePath.Substring(executablePath.LastIndexOf('\\') + 1) : executablePath;
isLauncherProcess = false; 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());
var newId = children.First(); if (process.Value.Path.Contains(executablePath) || process.Key.Contains(executableFile))
Debug.WriteLine($"Launcher opened child process ({runningProcessId}->{newId}), using new process as target"); {
runningProcessId = newId; 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 // Handle the last chance if process was not found due to slow running like Farming Simulator 2022 or Halo MCC
BringProcess(); secondCheck = !secondCheck;
return true; 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
} }
/// <summary> /// <summary>
/// Find pid<->parent_pid relationships /// Find process path with their dedicated pid
/// </summary> /// </summary>
/// <returns>Map of processes to their child IDs. Any process in this object may have already terminated</returns> /// <returns>Map of processes to their path and pid. Any process in this object may have already terminated</returns>
private static Dictionary<int, List<int>> GetProcessChildren() private static Dictionary<string, (string Path, int Pid)> GetProcess()
{ {
var result = new Dictionary<int, List<int>>(); var result = new Dictionary<string, (string Path, int Pid)>();
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()) foreach (var process in searcher.Get())
{ {
string processName = Convert.ToString(process.Properties["Name"].Value);
int processId = Convert.ToInt32(process.Properties["processid"].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)) if (String.IsNullOrWhiteSpace(processName) || result.ContainsKey(processName)) continue;
{
result.Add(parentId, new List<int>());
}
result[parentId].Add(processId); result.Add(processName, (processPath, processId));
} }
} }
@ -125,7 +151,7 @@ namespace UWPHook
} }
/// <summary> /// <summary>
/// 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 '|'
/// </summary> /// </summary>
/// <returns>List of installed UWP Apps</returns> /// <returns>List of installed UWP Apps</returns>
public static List<String> GetInstalledApps() public static List<String> GetInstalledApps()

Loading…
Cancel
Save