Skip to content

Commit ae3bee2

Browse files
Reimplemented process acquisition
... also added a user tuneable to allow customizing process wait timer
1 parent c43d031 commit ae3bee2

6 files changed

Lines changed: 76 additions & 88 deletions

File tree

Changelog.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
* 9c22010 (HEAD -> staging) Fixed some games not being detected if their launcher starts minimized
2-
* 5d2d665 (origin/staging) Bumped version number for point release
1+
* 1236acc (HEAD -> staging) Reimplemented process acquisition ... also added a user tuneable to allow customizing process wait timer
2+
* c43d031 (tag: v1.07f, origin/staging) Fixed some games not being detected if their launcher starts minimized
3+
* 5d2d665 Bumped version number for point release
34
* 19f0797 Fixed Epic Games Launcher not being detected in URI mode
45
* 9751f47 Code cleanup and abstraction from core Program class
56
* 3418ca5 (origin/master, origin/HEAD, master) Forgot periods in install bullets

OriginSteamOverlayLauncher/Form1.resx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,10 @@ PreLaunchExec=C:\Your PreLauncher\Executable.exe
133133
PreLaunchExecArgs=Your PreLauncher Executable Args Here
134134
PostGameExec=C:\Your PostGame\Executable.exe
135135
PostGameExecArgs=Your PostGame Executable Args Here
136-
PreGameOverlayWaitTime=5 (seconds to wait for overlay after launching launcher)
137-
PreGameLauncherWaitTime=12 (seconds to wait for launcher before launching game)
136+
PreGameLauncherWaitTime=5 (seconds to wait for launcher before launching game)
138137
PostGameWaitTime=7 (seconds to wait after game exits for cloud syncing)
139138
PostGameCommandWaitTime=7 (seconds to wait before post-game launch commands run)
140-
ProxyTimeout=5 (seconds to wait for launcher proxy to exit before detecting game PID)
139+
ProxyTimeout=2 (seconds to wait before attempts to validate process PIDs)
141140
LauncherMode=Normal (Normal mode launches the LauncherPath and GamePath)
142141
LauncherMode=LauncherOnly (LauncherOnly mode launches only the LauncherPath)
143142
LauncherMode=URI (URI mode launches LauncherPath with the argument in LauncherURI)
@@ -150,6 +149,7 @@ CommandlineProxy=False (set to True to copy token arguments from child game p
150149
ElevateExternals=False (set to True to run Pre/PostGameExec with elevated privileges)
151150
TerminateOSOLUponLaunch=False (set to True to request OSOL exit upon game/launcher launch)
152151
GameProcessAffinity=0,1,2,3 (set to a string of digits delimited by commas representing the target CPUs)
153-
GameProcessPriority= (can be Idle, BelowNormal, AboveNormal, High, or RealTime)</value>
152+
GameProcessPriority= (can be Idle, BelowNormal, AboveNormal, High, or RealTime)
153+
ProcessAcquisitionAttempts=5 (number of iterations before determining process validity)</value>
154154
</data>
155155
</root>

OriginSteamOverlayLauncher/ProcessTracking.cs

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,96 +11,53 @@ namespace OriginSteamOverlayLauncher
1111
{
1212
public class ProcessTracking
1313
{
14-
public static int ValidateProcTree(Process[] procTree, int timeout)
14+
public static int ValidateProcessByName(string procName, int timeout, int maxTimeout, int reattempts)
1515
{
16-
var procChildren = procTree.Count();
17-
Thread.Sleep(timeout * 1000); // let process stabilize before gathering data
18-
19-
if (procChildren == 1 && !procTree[0].HasExited
20-
&& (WindowUtils.HwndFromProc(procTree[0]) != IntPtr.Zero && procTree[0].MainWindowTitle.Length > 0) || procTree[0].Handle != IntPtr.Zero)
16+
int timeoutCounter = 0, _pid = 0, prevPID = 0, totalTime = 0; ;
17+
Process targetProc = null;
18+
while (timeoutCounter < maxTimeout)
2119
{
22-
procTree[0].Refresh();
23-
return procTree[0].Id; // just return the PID of the parent
24-
}
25-
else if (procChildren > 1)
26-
{// our parent is likely a caller or proxy
27-
for (int i = 0; i < procChildren; i++)
28-
{// iterate through each process in the tree and determine which process we should bind to
29-
var proc = procTree[i];
30-
proc.Refresh();
31-
32-
if (proc.Id > 0 && !proc.HasExited)
20+
for (int i = 0; i <= reattempts; i++)
21+
{
22+
targetProc = ProcessUtils.GetRunningProcByName(procName);
23+
targetProc.Refresh();
24+
Thread.Sleep(50);
25+
_pid = targetProc.Id;
26+
// wait for attempts to elapse (~10s by default) before validating the PID
27+
if (i == reattempts && _pid > 0 && _pid == prevPID &&
28+
ProcessUtils.IsValidProcess(targetProc))
3329
{
34-
if (WindowUtils.HwndFromProc(proc) != (IntPtr)null && !proc.SafeHandle.IsInvalid && proc.MainWindowTitle.Length > 0)
35-
{// probably a real process (launcher or game) because it has a real hwnd and title
36-
return proc.Id;
37-
}
38-
else if (!procTree[0].HasExited && WindowUtils.HwndFromProc(procTree[0]) == (IntPtr)null && procTree[0].MainWindowTitle.Length > 0)
39-
{// child returns an invalid hwnd, return the parent PID instead
40-
return procTree[0].Id;
41-
}
30+
int _time = (totalTime + 50) / 1000;
31+
ProcessUtils.Logger("OSOL", String.Format("Found a valid process at PID: {0} [{1}] in {2} seconds", _pid, String.Format("{0}.exe", procName), _time));
32+
return _pid;
4233
}
43-
}
4434

45-
for (int j = 0; j < procChildren; j++)
46-
{// fall back to finding the ModuleHandle (breaks window messages)
47-
var proc = procTree[j];
48-
if (proc.Id > 0 && WindowUtils.HwndFromProc(proc) == (IntPtr)null && proc.MainModule != null && (long)proc.Handle > 0)
49-
return proc.Id;
35+
prevPID = _pid;
36+
Thread.Sleep(timeout);
37+
totalTime += timeout+50;
5038
}
39+
timeoutCounter += totalTime;
5140
}
52-
41+
ProcessUtils.Logger("WARNING", String.Format("Could not bind to a valid process after waiting {0} seconds!", timeoutCounter));
5342
return 0;
5443
}
5544

56-
public static Process GetProcessTreeHandle(Settings setHnd, String procName, ref int processType)
57-
{// actively attempt to rebind process by PID via ValidateProcTree()
45+
public static Process GetProcessTreeHandle(Settings setHnd, string procName, ref int processType)
46+
{// actively attempt to rebind process by PID via ValidateProcessByName()
5847
int _result = 0;
5948
Process _retProc = null;
60-
int sanity_counter = 0;
6149
processType = -1;
6250

6351
ProcessUtils.Logger("OSOL", String.Format("Searching for valid process by name: {0}", procName));
64-
while (sanity_counter < setHnd.ProcessAcquisitionTimeout)
65-
{// loop every ProxyTimeout (via ValidateProcTree()) until we get a validated PID by procName
66-
var _procTree = ProcessUtils.GetProcessTreeByName(procName);
67-
// grab our first matching validated window PID
68-
_result = ValidateProcTree(_procTree, setHnd.ProxyTimeout);
69-
// update our counter for logging purposes
70-
sanity_counter = sanity_counter + setHnd.ProxyTimeout;
71-
72-
// first check if we should bail early due to timeout
73-
if (sanity_counter >= setHnd.ProcessAcquisitionTimeout)
74-
{
75-
ProcessUtils.Logger("WARNING", String.Format("Could not bind to a valid process after waiting {0} seconds!", setHnd.ProcessAcquisitionTimeout));
76-
break;
77-
}
52+
_result = ValidateProcessByName(procName, setHnd.ProxyTimeout * 1000, setHnd.ProcessAcquisitionTimeout * 1000, setHnd.ProcessAcquisitionAttempts);
7853

79-
#if DEBUG
80-
if (_procTree.Count() != 0)
81-
{
82-
StringBuilder _procOut = new StringBuilder();
83-
_procOut.Append("Trying to bind to detected processes at PIDs: ");
84-
85-
foreach (Process proc in _procTree)
86-
{
87-
_procOut.Append(proc.Id + " ");
88-
}
89-
ProcessUtils.Logger("DEBUG", _procOut.ToString());
90-
}
91-
#endif
92-
93-
if (_result > 0)
94-
{// rebind our process handle using our validated PID
95-
_retProc = ProcessUtils.RebindProcessByID(_result);
96-
processType = WindowUtils.DetectWindowType(_retProc); // pass our process type out by ref
97-
ProcessUtils.Logger("OSOL", String.Format("Bound to a valid process at PID: {0} [{1}] in {2} seconds", _result, String.Format("{0}.exe", procName), sanity_counter));
54+
if (_result > 0)
55+
{// rebind our process handle using our validated PID
56+
_retProc = ProcessUtils.RebindProcessByID(_result);
57+
processType = WindowUtils.DetectWindowType(_retProc); // pass our process type out by ref
9858

99-
if (processType == -1)
100-
ProcessUtils.Logger("WARNING", String.Format("Could not find MainWindowHandle of PID [{0}], fell back to ModuleHandle instead...", _retProc.Id));
101-
102-
break;
103-
}
59+
if (processType == -1)
60+
ProcessUtils.Logger("WARNING", String.Format("Could not find MainWindowHandle of PID [{0}], fell back to ModuleHandle instead...", _retProc.Id));
10461
}
10562

10663
return _retProc; // returns null if nothing matched or we timed out, otherwise reports a validated Process handle
@@ -208,7 +165,7 @@ public void ProcessLauncher(Settings setHnd, IniFile iniHnd)
208165
if (launcherType > -1)
209166
{// we can only send window messages if we have a window handle
210167
WindowUtils.BringToFront(WindowUtils.HwndFromProc(launcherProc));
211-
if (setHnd.MinimizeLauncher)
168+
if (setHnd.MinimizeLauncher && launcherProc.MainWindowHandle != IntPtr.Zero)
212169
WindowUtils.MinimizeWindow(WindowUtils.HwndFromProc(launcherProc));
213170
}
214171

@@ -378,7 +335,7 @@ public void ProcessLauncher(Settings setHnd, IniFile iniHnd)
378335
Thread.Sleep(1000);
379336

380337
// resend the message to minimize our launcher
381-
if (setHnd.MinimizeLauncher)
338+
if (setHnd.MinimizeLauncher && launcherProc.MainWindowHandle != IntPtr.Zero)
382339
WindowUtils.MinimizeWindow(WindowUtils.HwndFromProc(launcherProc));
383340

384341
// let Origin sync with the cloud

OriginSteamOverlayLauncher/ProcessUtils.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ public static int GetRunningPIDByName(String procName)
6262
return 0;
6363
}
6464

65+
public static int GetParentProcessByPID(int PID)
66+
{
67+
int _pid = 0;
68+
using (ManagementObject parentProcess = new ManagementObject("win32_process.handle='" + PID.ToString() + "'"))
69+
{
70+
parentProcess.Get();
71+
_pid = Convert.ToInt32(parentProcess["ParentProcessId"]);
72+
}
73+
return _pid;
74+
}
75+
76+
public static bool IsValidProcess(Process targetProc)
77+
{// rough process validation - must have an hwnd or handle
78+
if (!targetProc.HasExited &&
79+
WindowUtils.HwndFromProc(targetProc) != IntPtr.Zero &&
80+
targetProc.MainWindowTitle.Length > 0 ||
81+
targetProc.Handle != IntPtr.Zero)
82+
return true;
83+
return false;
84+
}
85+
86+
public static Process GetRunningProcByName(string procName)
87+
{
88+
return RebindProcessByID(GetRunningPIDByName(procName));
89+
}
90+
6591
public static Process RebindProcessByID(int PID)
6692
{// just a stub
6793
return Process.GetProcessById(PID);

OriginSteamOverlayLauncher/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.7.7")]
36-
[assembly: AssemblyFileVersion("1.0.7.7")]
35+
[assembly: AssemblyVersion("1.0.7.8")]
36+
[assembly: AssemblyFileVersion("1.0.7.8")]

OriginSteamOverlayLauncher/Settings.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class Settings
4747
public int PostGameCommandWaitTime { get; set; }
4848
public int ProxyTimeout { get; set; }
4949
public int ProcessAcquisitionTimeout { get; set; }
50+
public int ProcessAcquisitionAttempts { get; set; }
5051
#endregion
5152

5253
#region Helpers
@@ -132,11 +133,12 @@ public static bool CreateINI(Settings setHnd, IniFile iniHnd)
132133
iniHnd.Write("PostGameExecArgs", String.Empty, "Options");
133134

134135
// integer options (sensible defaults)
135-
iniHnd.Write("PreGameLauncherWaitTime", "12", "Options"); //12s
136+
iniHnd.Write("PreGameLauncherWaitTime", "5", "Options"); //5s
136137
iniHnd.Write("PostGameWaitTime", "7", "Options"); //7s
137138
iniHnd.Write("PostGameCommandWaitTime", "7", "Options"); //7s
138-
iniHnd.Write("ProxyTimeout", "3", "Options"); //3s
139+
iniHnd.Write("ProxyTimeout", "2", "Options"); //2s
139140
iniHnd.Write("ProcessAcquisitionTimeout", "300", "Options"); //5mins
141+
iniHnd.Write("ProcessAcquisitionAttempts", "5", "Options"); //5 attempts * ProxyTimeout (~10s)
140142

141143
// options as parsed strings
142144
// Kill and relaunch detected launcher PID before game
@@ -186,6 +188,7 @@ public static bool CheckINI(IniFile iniHnd)
186188
&& iniHnd.KeyExists("PreGameLauncherWaitTime")
187189
&& iniHnd.KeyExists("PostGameWaitTime")
188190
&& iniHnd.KeyExists("ProcessAcquisitionTimeout")
191+
&& iniHnd.KeyExists("ProcessAcquisitionAttempts")
189192
&& iniHnd.KeyExists("ProxyTimeout")
190193
&& iniHnd.KeyExists("ReLaunch")
191194
&& iniHnd.KeyExists("SkipLauncher")
@@ -399,9 +402,10 @@ public static bool ValidateINI(Settings setHnd, IniFile iniHnd, String iniFilePa
399402
setHnd.PostGameExecArgs = ValidateString(iniHnd, String.Empty, setHnd.PostGameExecArgs, "PostGameExecArgs", "Options");
400403

401404
// treat ints differently
402-
setHnd.ProxyTimeout = ValidateInt(iniHnd, 3, "ProxyTimeout", "Options"); // 3s default wait time
403-
setHnd.PreGameLauncherWaitTime = ValidateInt(iniHnd, 12, "PreGameLauncherWaitTime", "Options"); // 12s default wait time
404-
setHnd.ProcessAcquisitionTimeout = ValidateInt(iniHnd, 300, "ProcessAcquisitionTimeout", "Options"); // 5mins default wait time
405+
setHnd.ProxyTimeout = ValidateInt(iniHnd, 2, "ProxyTimeout", "Options"); // 3s default wait time
406+
setHnd.PreGameLauncherWaitTime = ValidateInt(iniHnd, 5, "PreGameLauncherWaitTime", "Options"); // 5s default wait time
407+
setHnd.ProcessAcquisitionTimeout = ValidateInt(iniHnd, 300, "ProcessAcquisitionTimeout", "Options"); // 5mins default max wait time
408+
setHnd.ProcessAcquisitionAttempts = ValidateInt(iniHnd, 5, "ProcessAcquisitionAttempts", "Options"); // 10s (5*ProxyTimeout) default max wait time
405409
setHnd.PostGameWaitTime = ValidateInt(iniHnd, 7, "PostGameWaitTime", "Options"); // 7s default wait time
406410
setHnd.PostGameCommandWaitTime = ValidateInt(iniHnd, 7, "PostGameCommandWaitTime", "Options"); // 7s default wait time
407411

0 commit comments

Comments
 (0)