diff --git a/UWPHook/AppEntry.cs b/UWPHook/AppEntry.cs
index 8df6091..3fe7736 100644
--- a/UWPHook/AppEntry.cs
+++ b/UWPHook/AppEntry.cs
@@ -35,6 +35,16 @@ namespace UWPHook
set { _name = value; }
}
+ private string _executable;
+ ///
+ /// Gets or sets the executable of the application
+ ///
+ public string Executable
+ {
+ get { return _executable; }
+ set { _executable = value; }
+ }
+
private string _aumid;
///
/// Gets or sets the aumid of the application
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()
diff --git a/UWPHook/GamesWindow.xaml.cs b/UWPHook/GamesWindow.xaml.cs
index 9043b43..ba1501a 100644
--- a/UWPHook/GamesWindow.xaml.cs
+++ b/UWPHook/GamesWindow.xaml.cs
@@ -1,4 +1,5 @@
using Force.Crc32;
+using Serilog;
using SharpSteam;
using System;
using System.Collections.Generic;
@@ -35,6 +36,10 @@ namespace UWPHook
Debug.WriteLine("Init GamesWindow");
Apps = new AppEntryModel();
var args = Environment.GetCommandLineArgs();
+ Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Error()
+ .WriteTo.File("debug.log", rollingInterval: RollingInterval.Day)
+ .CreateLogger();
// If null or 1, the app was launched normally
if (args?.Length > 1)
@@ -400,7 +405,7 @@ namespace UWPHook
AppName = app.Name,
Exe = exePath,
StartDir = exeDir,
- LaunchOptions = app.Aumid,
+ LaunchOptions = app.Aumid + " " + app.Executable,
AllowDesktopConfig = 1,
AllowOverlay = 1,
Icon = icon,
@@ -667,7 +672,7 @@ namespace UWPHook
string logosPath = Path.GetDirectoryName(values[1]);
Application.Current.Dispatcher.BeginInvoke((Action)delegate ()
{
- Apps.Entries.Add(new AppEntry() { Name = values[0], IconPath = logosPath, Aumid = values[2], Selected = false });
+ Apps.Entries.Add(new AppEntry() { Name = values[0], Executable = values[3], IconPath = logosPath, Aumid = values[2], Selected = false });
});
}
}
diff --git a/UWPHook/Resources/GetAUMIDScript.ps1 b/UWPHook/Resources/GetAUMIDScript.ps1
index e03e5ab..7007252 100644
--- a/UWPHook/Resources/GetAUMIDScript.ps1
+++ b/UWPHook/Resources/GetAUMIDScript.ps1
@@ -10,6 +10,11 @@ foreach ($app in $installedapps)
{
$appx = Get-AppxPackageManifest $app;
$name = $appx.Package.Properties.DisplayName;
+ $executable = (Select-Xml -Path ($app.InstallLocation + "\MicrosoftGame.Config") -XPath "/Game/ExecutableList/Executable/@Name").Node.Value
+ # Convert object to ensure is the String of execuble (cf Halo Master Chief Collection example below)
+ # mcclauncher.exe
+ # MCC\Binaries\Win64\MCCWinStore-Win64-Shipping.exe
+ if($executable -is [Object[]]) { $executable = $executable[1].ToString() }
if($name -like '*DisplayName*' -or $name -like '*ms-resource*')
{
@@ -22,8 +27,7 @@ foreach ($app in $installedapps)
$logo = $app.InstallLocation + "\" + $appx.Package.Applications.Application.VisualElements.Square150x150Logo;
- $aumidList += $name + "|" + $logo + "|" +
- $app.packagefamilyname + "!" + $id+ ";"
+ $aumidList += $name + "|" + $logo + "|" + $app.packagefamilyname + "!" + $id + "|" + $executable + ";"
}
}
}
diff --git a/UWPHook/UWPHook.csproj b/UWPHook/UWPHook.csproj
index de0049c..5885375 100644
--- a/UWPHook/UWPHook.csproj
+++ b/UWPHook/UWPHook.csproj
@@ -213,6 +213,12 @@
13.0.1
+
+ 2.11.0
+
+
+ 5.0.0
+