private async void OnGameExited(object sender, ProcessEventArgs e) { if (SetHnd.Options.MinimizeLauncher && LauncherPL.ProcWrapper.IsRunning()) { WindowUtils.MinimizeWindow(LauncherPL.ProcWrapper.Hwnd); } // run PostGameExecPath/Args after the game exits PostGamePL = new ProcessLauncher( SetHnd.Paths.PostGameExecPath, SetHnd.Paths.PostGameExecArgs, elevate: SetHnd.Options.ElevateExternals, delayTime: SetHnd.Options.PostGameWaitTime ); await PostGamePL.Launch(); if (SetHnd.Options.PostGameWaitTime > 0) { ProcessUtils.Logger("OSOL", $"Game exited, moving on to clean up after {SetHnd.Options.PostGameWaitTime}s..."); } else { ProcessUtils.Logger("OSOL", $"Game exited, cleaning up..."); } await Task.Delay(SetHnd.Options.PostGameWaitTime * 1000); if (SetHnd.Options.CloseLauncher && ProcessWrapper.IsRunningByName(LauncherName)) { ProcessUtils.Logger("OSOL", $"Found launcher still running, killing it..."); ProcessWrapper.KillProcTreeByName(LauncherName); } OnClosing(); }
public async Task ProcessLauncher() { // check for running instance of launcher (relaunch if required) if (SetHnd.Options.ReLaunch && LauncherPathValid && ProcessWrapper.IsRunningByName(LauncherName)) {// if the launcher is running before the game kill it so we can run it through Steam ProcessUtils.Logger("OSOL", $"Found previous instance of launcher [{LauncherName}.exe], relaunching..."); ProcessWrapper.KillProcTreeByName(LauncherName); } // run PreLaunchExecPath/Args before the launcher PreLauncherPL = new ProcessLauncher( SetHnd.Paths.PreLaunchExecPath, SetHnd.Paths.PreLaunchExecArgs, elevate: SetHnd.Options.ElevateExternals ); await PreLauncherPL.Launch(); LauncherPL = new ProcessLauncher( SetHnd.Paths.LauncherPath, SetHnd.Paths.LauncherArgs, avoidProcName: GameName ); if (!SetHnd.Options.SkipLauncher && SetHnd.Options.ReLaunch) { await LauncherPL.Launch(); // launching the launcher is optional } LauncherMonitor = new ProcessMonitor( LauncherPL, SetHnd.Options.ProcessAcquisitionTimeout, SetHnd.Options.InterProcessAcquisitionTimeout ); LauncherMonitor.ProcessHardExit += OnLauncherExited; // signal for manual game launch if (SetHnd.Options.SkipLauncher) { OnLauncherAcquired(this, null); } else { LauncherMonitor.ProcessAcquired += OnLauncherAcquired; } // wait for all running threads to exit while (!ExitRequested || PreLauncherPL != null && PreLauncherPL.ProcWrapper.IsRunning() || PostGamePL != null && PostGamePL.ProcWrapper.IsRunning() || LauncherMonitor != null && LauncherMonitor.IsRunning() || GameMonitor != null && GameMonitor.IsRunning()) { await Task.Delay(1000); } }
/// <summary> /// Threaded timer for monitoring and validating a process heuristically /// </summary> public ProcessMonitor(ProcessLauncher procLauncher, int globalTimeout, int innerTimeout) {// constructor for GamePath + MonitorPath instances TargetLauncher = procLauncher; GlobalTimeout = globalTimeout; InnerTimeout = innerTimeout; ProcessName = !string.IsNullOrWhiteSpace(TargetLauncher.MonitorName) ? TargetLauncher.MonitorName : TargetLauncher.ProcWrapper.ProcessName; MonitorLock = new SemaphoreSlim(1, 1); MonitorTimer = new Timer(MonitorProcess); SearchTimer = new Timer(SearchProcess); MonitorTimer.Change(0, Interval); }
/// <summary> /// Threaded timer for monitoring and validating a process heuristically /// </summary> public ProcessMonitor(ProcessLauncher procLauncher, int globalTimeout, int innerTimeout) {// constructor for GamePath + MonitorPath instances TargetLauncher = procLauncher; GlobalTimeout = globalTimeout; InnerTimeout = innerTimeout; if (TargetLauncher != null) { ProcessName = !string.IsNullOrWhiteSpace(TargetLauncher.MonitorName) ? TargetLauncher.MonitorName : TargetLauncher.ProcWrapper.ProcessName; } else { throw new ArgumentException("ProcessMonitor requires a valid ProcessLauncher instance!"); } MonitorLock = new SemaphoreSlim(1, 1); MonitorTimer = new Timer(MonitorProcess); SearchTimer = new Timer(SearchProcess); MonitorTimer.Change(0, Interval); }
private async void OnLauncherAcquired(object sender, ProcessEventArgs e) { // collect launcher information for collision avoidance int _type = LauncherPL?.ProcWrapper?.ProcessType ?? -1; bool _running = (bool)LauncherMonitor?.IsRunning(); int _aPID = e?.AvoidPID ?? 0; // MinimizeWindow after acquisition to prevent issues with ProcessType() fetch if (SetHnd.Options.MinimizeLauncher && LauncherPL.ProcWrapper.IsRunning()) { WindowUtils.MinimizeWindow(LauncherPL.ProcWrapper.Hwnd); } if (!SetHnd.Options.SkipLauncher && LauncherPathValid && LauncherPL != null) {// pause to let the launcher process stabilize after being hooked ProcessUtils.Logger("OSOL", $"Launcher detected (type {_type}), preparing to launch game in {SetHnd.Options.PreGameLauncherWaitTime}s..."); await Task.Delay(SetHnd.Options.PreGameLauncherWaitTime * 1000); } if (SetHnd.Options.SkipLauncher) { // ignore AutoGameLaunch option explicitly here if (LauncherURIMode) // URI mode { GamePL = new ProcessLauncher( SetHnd.Paths.LauncherURI, "", avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, monitorName: GameName ); } else // normal SkipLauncher behavior { GamePL = new ProcessLauncher( SetHnd.Paths.GamePath, SetHnd.Paths.GameArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, monitorName: MonitorName ); } await GamePL.Launch(); } else { if (_running && LauncherURIMode) // URIs { GamePL = new ProcessLauncher( SetHnd.Paths.LauncherURI, "", avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: GameName ); } else if (_running && _type == 1) // Battle.net (relaunch LauncherArgs) { GamePL = new ProcessLauncher( SetHnd.Paths.LauncherPath, SetHnd.Paths.LauncherArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: GameName ); } else if (LauncherPathValid && _running) // normal behavior { GamePL = new ProcessLauncher( SetHnd.Paths.GamePath, SetHnd.Paths.GameArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: MonitorName ); } if (GamePL != null && (LauncherPathValid && _running || SetHnd.Options.AutoGameLaunch)) { await GamePL?.Launch(); // only launch if safe to do so } else if (LauncherPathValid && LauncherMonitor.IsRunning()) { ProcessUtils.Logger("OSOL", "AutoGameLaunch is false, waiting for user to launch game before timing out..."); } } GameMonitor = new ProcessMonitor( GamePL, SetHnd.Options.ProcessAcquisitionTimeout, SetHnd.Options.InterProcessAcquisitionTimeout ); GameMonitor.ProcessAcquired += OnGameAcquired; GameMonitor.ProcessHardExit += OnGameExited; }
private async void OnLauncherAcquired(object sender, ProcessEventArgs e) { int _type = -1; bool _running = false; int _aPID = 0; if (LauncherPL != null && LauncherMonitor != null) {// collect launcher information for collision avoidance _type = LauncherPL?.ProcWrapper?.ProcessType ?? -1; _running = LauncherMonitor.IsRunning(); _aPID = e?.AvoidPID ?? 0; } if (LauncherPL != null && LauncherPL.ProcWrapper.IsRunning()) { // MinimizeWindow after acquisition to prevent issues with ProcessType() fetch if (SetHnd.Options.MinimizeLauncher) { WindowUtils.MinimizeWindow(LauncherPL.ProcWrapper.Hwnd); } // pause to let the launcher process stabilize after being hooked if (!SetHnd.Options.SkipLauncher) { if (GamePathValid && SetHnd.Options.AutoGameLaunch) { ProcessUtils.Logger("OSOL", $"Launcher detected (type {_type}), preparing to launch game in {SetHnd.Options.PreGameLauncherWaitTime}s..."); } else { ProcessUtils.Logger("OSOL", $"Launcher detected (type {_type}), skipping GamePath, monitoring..."); } await Task.Delay(SetHnd.Options.PreGameLauncherWaitTime * 1000); } } if (SetHnd.Options.SkipLauncher && GamePathValid || LauncherURIMode) { // ignore AutoGameLaunch option explicitly here if (LauncherURIMode) // URI mode { GamePL = new ProcessLauncher( SetHnd.Paths.LauncherURI, "", avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, monitorName: GameName ); } else // normal SkipLauncher behavior { GamePL = new ProcessLauncher( SetHnd.Paths.GamePath, SetHnd.Paths.GameArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, monitorName: MonitorName ); } if (GamePL != null) { await GamePL.Launch(); } } else { if (_running && LauncherURIMode) // URIs { GamePL = new ProcessLauncher( SetHnd.Paths.LauncherURI, "", avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: GameName ); } else if (_running && _type == 1) // Battle.net (relaunch LauncherArgs) { // Battle.net v1 GamePL = new ProcessLauncher( SetHnd.Paths.LauncherPath, SetHnd.Paths.LauncherArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: GameName ); // Battle.net v2 doesn't launch via LauncherArgs so send Enter to the launcher if (ProcessUtils.OrdinalContains("productcode=", SetHnd.Paths.LauncherArgs)) { WindowUtils.SendEnterToForeground(LauncherPL.ProcWrapper.Hwnd); } } else if (GamePathValid) // normal behavior { GamePL = new ProcessLauncher( SetHnd.Paths.GamePath, SetHnd.Paths.GameArgs, avoidProcName: LauncherName, delayTime: SetHnd.Options.PreGameWaitTime, avoidPID: _aPID, monitorName: MonitorName ); } else if (!_running) { // edge case for !AutoGameLaunch while LauncherPathValid/GamePathValid ProcessUtils.Logger("FATAL", "Fell through all launch attempts, this should not happen!"); Environment.Exit(0); } if (GamePL != null && GamePathValid && !SetHnd.Options.AutoGameLaunch) { await GamePL?.Launch(NoLaunch : true); // monitor passively } else if (GamePL != null && (LauncherPathValid && _running || SetHnd.Options.AutoGameLaunch)) { await GamePL?.Launch(); // launch if safe to do so } else if (LauncherPathValid && LauncherMonitor.IsRunning()) { ProcessUtils.Logger("OSOL", $"AutoGameLaunch is false, continuing to monitor existing processes..."); } } if (GamePL != null) { // monitor only if safe to do so GameMonitor = new ProcessMonitor( GamePL, SetHnd.Options.ProcessAcquisitionTimeout, SetHnd.Options.InterProcessAcquisitionTimeout ); GameMonitor.ProcessAcquired += OnGameAcquired; GameMonitor.ProcessHardExit += OnGameExited; } }