diff --git a/DisplayMagician/ShortcutItem.cs b/DisplayMagician/ShortcutItem.cs index 5238611..d8aa9c1 100644 --- a/DisplayMagician/ShortcutItem.cs +++ b/DisplayMagician/ShortcutItem.cs @@ -1373,6 +1373,8 @@ namespace DisplayMagician int gameTimeout, string gameArguments, bool gameArgumentsRequired, + string differentGameExeToMonitor, + bool monitorDifferentGameExe, ShortcutPermanence displayPermanence, ShortcutPermanence audioPermanence, ShortcutPermanence capturePermanence, @@ -1401,6 +1403,8 @@ namespace DisplayMagician _startTimeout = gameTimeout; _gameArguments = gameArguments; _gameArgumentsRequired = gameArgumentsRequired; + _differentGameExeToMonitor = differentGameExeToMonitor; + _monitorDifferentGameExe = monitorDifferentGameExe; _changeAudioDevice = changeAudioDevice; _audioDevice = audioDevice; _setAudioVolume = setAudioVolume; @@ -1466,6 +1470,8 @@ namespace DisplayMagician _startTimeout = game.StartTimeout; _gameArguments = game.GameArguments; _gameArgumentsRequired = game.GameArgumentsRequired; + _differentGameExeToMonitor = game.DifferentGameExeToMonitor; + _monitorDifferentGameExe = game.MonitorDifferentGameExe; _changeAudioDevice = changeAudioDevice; _audioDevice = audioDevice; _setAudioVolume = setAudioVolume; @@ -1530,7 +1536,8 @@ namespace DisplayMagician _startTimeout = game.StartTimeout; _gameArguments = game.GameArguments; _gameArgumentsRequired = game.GameArgumentsRequired; - _gameArgumentsRequired = false; + _differentGameExeToMonitor = game.DifferentGameExeToMonitor; + _monitorDifferentGameExe = game.MonitorDifferentGameExe; _changeAudioDevice = changeAudioDevice; _audioDevice = audioDevice; _setAudioVolume = setAudioVolume; diff --git a/DisplayMagician/ShortcutRepository.cs b/DisplayMagician/ShortcutRepository.cs index 90be55c..722e3c7 100644 --- a/DisplayMagician/ShortcutRepository.cs +++ b/DisplayMagician/ShortcutRepository.cs @@ -963,7 +963,7 @@ namespace DisplayMagician // make sure we have things to monitor and alert if not if (processesToMonitor.Count == 0) { - logger.Error($"No '{processNameToLookFor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout"); + logger.Error($"ShortcutRepository/RunShortcut: No '{processNameToLookFor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout"); } // Store the process to monitor for later @@ -1002,7 +1002,6 @@ namespace DisplayMagician Thread.Sleep(2000); // if we have things to monitor, then we should start to wait for them - Console.WriteLine($"Waiting for all {processNameToLookFor} windows to exit."); logger.Debug($"ShortcutRepository/RunShortcut: Waiting for application {processNameToLookFor} to exit."); if (processesToMonitor.Count > 0) { @@ -1024,7 +1023,6 @@ namespace DisplayMagician Thread.Sleep(1000); } } - Console.WriteLine($"{processNameToLookFor} has exited."); logger.Debug($"ShortcutRepository/RunShortcut: Executable {processNameToLookFor} has exited."); @@ -1138,95 +1136,202 @@ namespace DisplayMagician } - // Delay 1secs - Thread.Sleep(1000); + // Delay 5secs + Thread.Sleep(5000); logger.Debug($"ShortcutRepository/RunShortcut: Pausing to let the game library start the game."); - // Now we know the game library app is running then - // we wait until the game has started running (*allows for updates to occur) - for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500) - { - - if (gameToRun.IsRunning) - { - // The game is running! So now we restart - logger.Debug($"ShortcutRepository/RunShortcut: Found the '{gameToRun.Name}' process has started"); - break; - } - - // Delay 500ms - Thread.Sleep(500); - - } - - // Store the Origin Process ID for later + // Store the Process ID for later //IPCService.GetInstance().HoldProcessId = gameLibraryProcesses.FirstOrDefault()?.Id ?? 0; //IPCService.GetInstance().Status = InstanceStatus.OnHold; - - // Add a status notification icon in the status area - if (gameToRun.Name.Length <= 41) - notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name}..."; - else - notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name.Substring(0, 41)}..."; - Application.DoEvents(); - - // Now we want to tell the user we're running a game! - // Construct the Windows toast content - tcBuilder = new ToastContentBuilder() - .AddToastActivationInfo("notify=runningOriginGame", ToastActivationType.Foreground) - .AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1) - .AddText($"Waiting for the Origin Game {gameToRun.Name} to exit..."); - //.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop"); - toastContent = tcBuilder.Content; - // Make sure to use Windows.Data.Xml.Dom - doc = new XmlDocument(); - doc.LoadXml(toastContent.GetContent()); - // And create the toast notification - toast = new ToastNotification(doc); - // Remove any other Notifications from us - DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); - // And then show this notification - DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); - - // Wait 5 seconds for the game process to spawn - Thread.Sleep(5000); - - // This is the main waiting thread! - // Wait for the game to exit - Console.WriteLine($"Waiting for {gameToRun.Name} to exit."); - logger.Debug($"ShortcutRepository/RunShortcut: waiting for Origin Game {gameToRun.Name} to exit."); - while (true) + + // At this point, if the user wants to actually monitor a different process, + // then we actually need to monitor that instead + if (shortcutToUse.MonitorDifferentGameExe) { - if (!gameToRun.IsRunning) + // If we are monitoring a different executable rather than the game itself, then lets get that name ready instead + string altGameProcessToMonitor = System.IO.Path.GetFileNameWithoutExtension(shortcutToUse.DifferentGameExeToMonitor); + + // Add a status notification icon in the status area + if (gameToRun.Name.Length <= 41) + notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name}..."; + else + notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name.Substring(0, 41)}..."; + Application.DoEvents(); + + // Now we want to tell the user we're running a game! + // Construct the Windows toast content + tcBuilder = new ToastContentBuilder() + .AddToastActivationInfo($"notify=running{gameLibraryToUse.GameLibraryName}Game", ToastActivationType.Foreground) + .AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1) + .AddText($"Waiting for the {altGameProcessToMonitor} alternative game process to exit..."); + //.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop"); + toastContent = tcBuilder.Content; + // Make sure to use Windows.Data.Xml.Dom + doc = new XmlDocument(); + doc.LoadXml(toastContent.GetContent()); + // And create the toast notification + toast = new ToastNotification(doc); + // Remove any other Notifications from us + DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); + // And then show this notification + DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); + + // Now look for the thing we're supposed to monitor + // and wait until it starts up + List processesToMonitor = new List(); + for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500) { - logger.Debug($"ShortcutRepository/RunShortcut: Origin Game {gameToRun.Name} is no longer running (IsRunning is false)."); - break; + // Look for the processes with the ProcessName we sorted out earlier + processesToMonitor = Process.GetProcessesByName(altGameProcessToMonitor).ToList(); + + // If we have found one or more processes then we should be good to go + // so let's break + if (processesToMonitor.Count > 0) + { + logger.Debug($"ShortcutRepository/RunShortcut: Found {processesToMonitor.Count} '{altGameProcessToMonitor}' processes to monitor"); + break; + } + + // Let's wait a little while if we couldn't find + // any processes yet + Thread.Sleep(500); + } + // make sure we have things to monitor and alert if not + if (processesToMonitor.Count == 0) + { + logger.Error($"ShortcutRepository/RunShortcut: No Alternative Game Executable '{altGameProcessToMonitor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout"); } - // Send a message to windows so that it doesn't think - // we're locked and try to kill us - System.Threading.Thread.CurrentThread.Join(0); - Thread.Sleep(1000); - } - Console.WriteLine($"{gameToRun.Name} has exited."); - logger.Debug($"ShortcutRepository/RunShortcut: Origin Game {gameToRun.Name} has exited."); + // if we have things to monitor, then we should start to wait for them + logger.Debug($"ShortcutRepository/RunShortcut: Waiting for alternative game proocess {altGameProcessToMonitor} to exit."); + if (processesToMonitor.Count > 0) + { + logger.Debug($"ShortcutRepository/RunShortcut: {processesToMonitor.Count} Alternative Game Executable '{altGameProcessToMonitor}' processes are still running"); + while (true) + { + processesToMonitor = Process.GetProcessesByName(altGameProcessToMonitor).ToList(); + + // If we have no more processes left then we're done! + if (processesToMonitor.Count == 0) + { + logger.Debug($"ShortcutRepository/RunShortcut: No more '{altGameProcessToMonitor}' processes are still running"); + break; + } + + // Send a message to windows so that it doesn't think + // we're locked and try to kill us + System.Threading.Thread.CurrentThread.Join(0); + Thread.Sleep(1000); + } + } + logger.Debug($"ShortcutRepository/RunShortcut: Alternative Game Executable {altGameProcessToMonitor} has exited."); + + // Tell the user that the Alt Game Executable has closed + // Construct the toast content + tcBuilder = new ToastContentBuilder() + .AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground) + .AddText($"{altGameProcessToMonitor} was closed", hintMaxLines: 1) + .AddText($"{altGameProcessToMonitor} alternative game executable was exited."); + toastContent = tcBuilder.Content; + // Make sure to use Windows.Data.Xml.Dom + doc = new XmlDocument(); + doc.LoadXml(toastContent.GetContent()); + // And create the toast notification + toast = new ToastNotification(doc); + // Remove any other Notifications from us + DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); + // And then show it + DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); + + } + else + { + // we are monitoring the game thats actually running (the most common scenario) + + // Add a status notification icon in the status area + if (gameToRun.Name.Length <= 41) + notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name}..."; + else + notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name.Substring(0, 41)}..."; + Application.DoEvents(); + + // Now we want to tell the user we're running a game! + // Construct the Windows toast content + tcBuilder = new ToastContentBuilder() + .AddToastActivationInfo($"notify=running{gameLibraryToUse.GameLibraryName}Game", ToastActivationType.Foreground) + .AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1) + .AddText($"Waiting for the {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} to exit..."); + //.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop"); + toastContent = tcBuilder.Content; + // Make sure to use Windows.Data.Xml.Dom + doc = new XmlDocument(); + doc.LoadXml(toastContent.GetContent()); + // And create the toast notification + toast = new ToastNotification(doc); + // Remove any other Notifications from us + DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); + // And then show this notification + DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); + + + // Now we know the game library app is running then + // we wait until the game has started running (*allows for updates to occur) + for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500) + { + + if (gameToRun.IsRunning) + { + // The game is running! So now we continue processing + logger.Debug($"ShortcutRepository/RunShortcut: Found the '{gameToRun.Name}' process has started"); + break; + } + + // Delay 500ms + Thread.Sleep(500); + + } + + // Wait 5 more seconds for the game process to spawn + // Thread.Sleep(5000); + + // This is the main waiting thread! + // Wait for the game to exit + logger.Debug($"ShortcutRepository/RunShortcut: waiting for {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} to exit."); + while (true) + { + if (!gameToRun.IsRunning) + { + logger.Debug($"ShortcutRepository/RunShortcut: {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} is no longer running (IsRunning is false)."); + break; + } + + // Send a message to windows so that it doesn't think + // we're locked and try to kill us + System.Threading.Thread.CurrentThread.Join(0); + Thread.Sleep(1000); + } + Console.WriteLine($"{gameToRun.Name} has exited."); + logger.Debug($"ShortcutRepository/RunShortcut: {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} has exited."); + + // Tell the user that the Game has closed + // Construct the toast content + tcBuilder = new ToastContentBuilder() + .AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground) + .AddText($"{shortcutToUse.GameName} was closed", hintMaxLines: 1) + .AddText($"{shortcutToUse.GameName} game was exited."); + toastContent = tcBuilder.Content; + // Make sure to use Windows.Data.Xml.Dom + doc = new XmlDocument(); + doc.LoadXml(toastContent.GetContent()); + // And create the toast notification + toast = new ToastNotification(doc); + // Remove any other Notifications from us + DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); + // And then show it + DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); + + } - // Tell the user that the Uplay Game has closed - // Construct the toast content - tcBuilder = new ToastContentBuilder() - .AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground) - .AddText($"{shortcutToUse.GameName} was closed", hintMaxLines: 1) - .AddText($"{shortcutToUse.GameName} game was shutdown and changes were reverted."); - toastContent = tcBuilder.Content; - // Make sure to use Windows.Data.Xml.Dom - doc = new XmlDocument(); - doc.LoadXml(toastContent.GetContent()); - // And create the toast notification - toast = new ToastNotification(doc); - // Remove any other Notifications from us - DesktopNotifications.DesktopNotificationManagerCompat.History.Clear(); - // And then show it - DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast); } else { diff --git a/DisplayMagician/UIForms/ShortcutForm.Designer.cs b/DisplayMagician/UIForms/ShortcutForm.Designer.cs index 52629f9..90607d2 100644 --- a/DisplayMagician/UIForms/ShortcutForm.Designer.cs +++ b/DisplayMagician/UIForms/ShortcutForm.Designer.cs @@ -1319,6 +1319,7 @@ namespace DisplayMagician.UIForms this.btn_choose_alternative_game.TabIndex = 26; this.btn_choose_alternative_game.Text = "Choose"; this.btn_choose_alternative_game.UseVisualStyleBackColor = true; + this.btn_choose_alternative_game.Click += new System.EventHandler(this.btn_choose_alternative_game_Click); // // txt_alternative_game // diff --git a/DisplayMagician/UIForms/ShortcutForm.cs b/DisplayMagician/UIForms/ShortcutForm.cs index fc51aae..5e987cb 100644 --- a/DisplayMagician/UIForms/ShortcutForm.cs +++ b/DisplayMagician/UIForms/ShortcutForm.cs @@ -308,6 +308,26 @@ namespace DisplayMagician.UIForms return; } + if (cb_wait_alternative_game.Checked && String.IsNullOrWhiteSpace(txt_alternative_game.Text)) + { + MessageBox.Show( + $"If you want to wait for an alternative game executable then you need to choose it! Click the 'Choose' button next to the different game executable field.", + @"Need to choose the different game executable", + MessageBoxButtons.OK, + MessageBoxIcon.Exclamation); + return; + } + + if (cb_wait_alternative_game.Checked && !File.Exists(txt_alternative_game.Text)) + { + MessageBox.Show( + @"The alternative game executable you have chosen does not exist! Please reselect the alternative game executable, or check you have permissions to view it.", + @"Alternative game executable doesn't exist", + MessageBoxButtons.OK, + MessageBoxIcon.Exclamation); + return; + } + } @@ -483,116 +503,58 @@ namespace DisplayMagician.UIForms if (rb_launcher.Checked) { logger.Trace($"ShortcutForm/btn_save_Click: We're saving a game!"); + + _gameToUse = new GameStruct + { + StartTimeout = Convert.ToInt32(nud_timeout_game.Value), + GameArguments = txt_args_game.Text, + GameArgumentsRequired = cb_args_game.Checked, + DifferentGameExeToMonitor = txt_alternative_game.Text, + MonitorDifferentGameExe = cb_wait_alternative_game.Checked + }; + // If the game is a SteamGame if (txt_game_launcher.Text == SupportedGameLibraryType.Steam.ToString()) { logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Steam game!"); // Find the SteamGame - _gameToUse = new GameStruct - { - GameToPlay = (from steamGame in SteamLibrary.GetLibrary().AllInstalledGames where steamGame.Id == _gameId select steamGame).First(), - StartTimeout = Convert.ToInt32(nud_timeout_game.Value), - GameArguments = txt_args_game.Text, - GameArgumentsRequired = cb_args_game.Checked, - DifferentGameExeToMonitor = txt_alternative_game.Text, - MonitorDifferentGameExe = cb_wait_alternative_game.Checked - }; - - _shortcutToEdit.UpdateGameShortcut( - txt_shortcut_save_name.Text, - _profileToUse, - _gameToUse, - _displayPermanence, - _audioPermanence, - _capturePermanence, - _gameToUse.GameToPlay.IconPath, - _changeAudioDevice, - _audioDevice, - _setAudioVolume, - _audioVolume, - _changeCaptureDevice, - _captureDevice, - _setCaptureVolume, - _captureVolume, - _startPrograms, - _autoName, - _uuid - ); + _gameToUse.GameToPlay = (from steamGame in SteamLibrary.GetLibrary().AllInstalledGames where steamGame.Id == _gameId select steamGame).First(); } // If the game is a UplayGame else if (txt_game_launcher.Text == SupportedGameLibraryType.Uplay.ToString()) { logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Uplay game!"); // Find the UplayGame - _gameToUse = new GameStruct - { - GameToPlay = (from uplayGame in UplayLibrary.GetLibrary().AllInstalledGames where uplayGame.Id == _gameId select uplayGame).First(), - StartTimeout = Convert.ToInt32(nud_timeout_game.Value), - GameArguments = txt_args_game.Text, - GameArgumentsRequired = cb_args_game.Checked, - DifferentGameExeToMonitor = txt_alternative_game.Text, - MonitorDifferentGameExe = cb_wait_alternative_game.Checked - }; - - _shortcutToEdit.UpdateGameShortcut( - txt_shortcut_save_name.Text, - _profileToUse, - _gameToUse, - _displayPermanence, - _audioPermanence, - _capturePermanence, - _gameToUse.GameToPlay.IconPath, - _changeAudioDevice, - _audioDevice, - _setAudioVolume, - _audioVolume, - _changeCaptureDevice, - _captureDevice, - _setCaptureVolume, - _captureVolume, - _startPrograms, - _autoName, - _uuid - ); - + _gameToUse.GameToPlay = (from uplayGame in UplayLibrary.GetLibrary().AllInstalledGames where uplayGame.Id == _gameId select uplayGame).First(); } // If the game is an Origin Game else if (txt_game_launcher.Text == SupportedGameLibraryType.Origin.ToString()) { - // Find the OriginGame - _gameToUse = new GameStruct - { - GameToPlay = (from originGame in OriginLibrary.GetLibrary().AllInstalledGames where originGame.Id == _gameId select originGame).First(), - StartTimeout = Convert.ToInt32(nud_timeout_game.Value), - GameArguments = txt_args_game.Text, - GameArgumentsRequired = cb_args_game.Checked, - DifferentGameExeToMonitor = txt_alternative_game.Text, - MonitorDifferentGameExe = cb_wait_alternative_game.Checked - }; - - _shortcutToEdit.UpdateGameShortcut( - txt_shortcut_save_name.Text, - _profileToUse, - _gameToUse, - _displayPermanence, - _audioPermanence, - _capturePermanence, - _gameToUse.GameToPlay.IconPath, - _changeAudioDevice, - _audioDevice, - _setAudioVolume, - _audioVolume, - _changeCaptureDevice, - _captureDevice, - _setCaptureVolume, - _captureVolume, - _startPrograms, - _autoName, - _uuid - ); - + logger.Trace($"ShortcutForm/btn_save_Click: We're saving an Origin game!"); + _gameToUse.GameToPlay = (from originGame in OriginLibrary.GetLibrary().AllInstalledGames where originGame.Id == _gameId select originGame).First(); } + + _shortcutToEdit.UpdateGameShortcut( + txt_shortcut_save_name.Text, + _profileToUse, + _gameToUse, + _displayPermanence, + _audioPermanence, + _capturePermanence, + _gameToUse.GameToPlay.IconPath, + _changeAudioDevice, + _audioDevice, + _setAudioVolume, + _audioVolume, + _changeCaptureDevice, + _captureDevice, + _setCaptureVolume, + _captureVolume, + _startPrograms, + _autoName, + _uuid + ); } else if (rb_standalone.Checked) { @@ -1345,7 +1307,8 @@ namespace DisplayMagician.UIForms { if (_loadedShortcut) _isUnsaved = true; - if (File.Exists(dialog_open.FileName) && Path.GetExtension(dialog_open.FileName) == @".exe") + string fileExt = Path.GetExtension(dialog_open.FileName); + if (File.Exists(dialog_open.FileName) && (fileExt == @".exe" || fileExt == @".com")) { txt_alternative_executable.Text = dialog_open.FileName; dialog_open.FileName = string.Empty; @@ -2239,5 +2202,28 @@ namespace DisplayMagician.UIForms btn_choose_alternative_game.Enabled = false; } } + + private void btn_choose_alternative_game_Click(object sender, EventArgs e) + { + if (dialog_open.ShowDialog(this) == DialogResult.OK) + { + if (_loadedShortcut) + _isUnsaved = true; + string fileExt = Path.GetExtension(dialog_open.FileName); + if (File.Exists(dialog_open.FileName) && (fileExt == @".exe" || fileExt == @".com")) + { + txt_alternative_game.Text = dialog_open.FileName; + dialog_open.FileName = string.Empty; + } + else + { + MessageBox.Show( + Language.Selected_file_is_not_a_valid_file, + Language.Executable, + MessageBoxButtons.OK, + MessageBoxIcon.Exclamation); + } + } + } } } \ No newline at end of file