From 2ae9af7358f5d43542455d1920d567250c6bb329 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Mon, 11 Nov 2024 16:24:37 +0200 Subject: [PATCH 01/14] Implement ExplorerMonitor Fixes crash-restart-loop issues: https://github.com/dremin/RetroBar/issues/942 https://github.com/dremin/RetroBar/issues/938 https://github.com/dremin/RetroBar/issues/927 https://github.com/dremin/RetroBar/issues/648 https://github.com/dremin/RetroBar/issues/476 https://github.com/dremin/RetroBar/issues/457 Co-Authored-By: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> --- RetroBar/Utilities/WindowManager.cs | 106 ++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 11c16fb0..96e2a46e 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -3,6 +3,8 @@ using ManagedShell.Common.Logging; using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; using System.Windows.Forms; namespace RetroBar.Utilities @@ -18,12 +20,19 @@ public class WindowManager : IDisposable private readonly ShellManager _shellManager; private readonly Updater _updater; + private readonly int _monitorUpdateDelay = 500; // Update delay in ms for explorer monitor thread. NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! + private volatile bool _monitoring; + private Thread _monitorThread; + private int _lastExplorerPid = -1; + public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { _shellManager = shellManager; _startMenuMonitor = startMenuMonitor; _updater = updater; + ExplorerMonitorStart(); + _shellManager.ExplorerHelper.HideExplorerTaskbar = true; openTaskbars(); @@ -186,5 +195,102 @@ public void Dispose() _shellManager.ExplorerHelper.HideExplorerTaskbar = false; Settings.Instance.PropertyChanged -= Settings_PropertyChanged; } + + public void ExplorerMonitorStart() + { + // Restarting RetroBar when explorer.exe is shutdown + // will allow explorer to initialize properly, + // this fixes "explorer restart loop bug". + + // Prevent multiple monitor threads + if(_monitoring){return;} + + _monitoring = true; // Set flag to true + + // Start monitor thread + _monitorThread = new Thread(() => + { + while (_monitoring) // This "while" loop is basically the main loop of the monitor thread. + { + try + { + // Get the current explorer.exe process + Process[] explorerProcesses = Process.GetProcessesByName("explorer"); + + if (explorerProcesses.Length == 0) // explorer.exe is not running + { + // Only act if previously tracked explorer was running + if (Interlocked.CompareExchange(ref _lastExplorerPid, 0, 0) != -1) + { + // If we landed here, this might indicate that explorer is trying to start but failing, + // so we will restart RetroBar just in case RetroBar is crashing explorer. + RestartRetroBar(); + } + } + else // explorer.exe is running + { + // Update current PID + int currentExplorerPid = explorerProcesses[0].Id; + + // Check if PID has changed + int lastExplorerPid = Interlocked.CompareExchange(ref _lastExplorerPid, 0, 0); + if (lastExplorerPid != -1 && lastExplorerPid != currentExplorerPid) + { + // Explorer PID was changed (explorer has restarted), so we will restart RetroBar. + RestartRetroBar(); + } + + // Update the tracked PID + Interlocked.Exchange(ref _lastExplorerPid, currentExplorerPid); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error monitoring explorer.exe: {ex.Message}"); + } + + // Sleep for a short interval to avoid excessive CPU usage. + // CPU usage was 0.00% with 500ms delay on test system. + // Increase _monitorUpdateDelay value to decrease CPU usage if needed. + // 500ms should be fine, unless your system is a potato. + // NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! + Thread.Sleep(_monitorUpdateDelay); + } + }); + + _monitorThread.IsBackground = true; // Ensure our monitor thread exits when RetroBar is shutdown. + _monitorThread.Start(); + } + + private static void RestartRetroBar() + { + // RestartRetroBar function is called if we detect that explorer.exe PID has changed. + + // Get RetroBar application path + string appPath = Process.GetCurrentProcess().MainModule?.FileName; + + if (!string.IsNullOrEmpty(appPath)) + { + try + { + // Start a new instance before killing the current process. + // There is a delay on RetroBar init so this is fine. + // NOTE: If the start delay of RetroBar is shortened or removed in the future, + // we will need to add a delay here. + Process.Start(appPath); + } + catch (Exception ex) + { + Console.WriteLine($"Error restarting RetroBar: {ex.Message}"); + } + + // Exit current RetroBar process. + Environment.Exit(0); + } + else + { + throw new InvalidOperationException("Unable to determine the path of RetroBar."); + } + } } } From e97d00eecb6df7bb4790dd6cad66fa06d6fa4ebb Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 00:57:03 +0200 Subject: [PATCH 02/14] Update ExplorerMonitor -Added ability to detect the main shell process so we dont accidentally target File Explorers or such -Added suport for custom shells -Some other minor tweaks --- RetroBar/Utilities/WindowManager.cs | 200 ++++++++++++++++++++++------ 1 file changed, 161 insertions(+), 39 deletions(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 96e2a46e..29afffd8 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -1,11 +1,14 @@ -using ManagedShell; +using ManagedShell; using ManagedShell.AppBar; using ManagedShell.Common.Logging; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; +using Microsoft.Win32; namespace RetroBar.Utilities { @@ -20,10 +23,12 @@ public class WindowManager : IDisposable private readonly ShellManager _shellManager; private readonly Updater _updater; - private readonly int _monitorUpdateDelay = 500; // Update delay in ms for explorer monitor thread. NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! - private volatile bool _monitoring; - private Thread _monitorThread; - private int _lastExplorerPid = -1; + private readonly int _ExplorerMonitorUpdateDelay = 300; // Update delay in ms for explorer monitor thread. NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! + private volatile bool _ExplorerMonitorIsMonitoring; + private Thread _ExplorerMonitorThread; + private int _ExplorerMonitorLastExplorerPid = -1; + [DllImport("user32.dll")] private static extern IntPtr GetShellWindow(); + [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -198,50 +203,81 @@ public void Dispose() public void ExplorerMonitorStart() { - // Restarting RetroBar when explorer.exe is shutdown - // will allow explorer to initialize properly, - // this fixes "explorer restart loop bug". + // Restarting RetroBar when Explorer is shutdown + // will allow Explorer to initialize properly, + // this fixes crash-restart-loop bug. - // Prevent multiple monitor threads - if(_monitoring){return;} + // Prevent multiple monitor threads. + if(_ExplorerMonitorIsMonitoring){return;} - _monitoring = true; // Set flag to true + _ExplorerMonitorIsMonitoring = true; // Set flag to true, to prevent multiple monitor threads. - // Start monitor thread - _monitorThread = new Thread(() => + // Get the expected shell (Explorer) executable name and path from the registry. + string shellExecutableName = GetShellExecutableNameFromRegistry(); + string expectedShellPath = GetShellPathFromRegistry(); + + // Start monitor thread. + _ExplorerMonitorThread = new Thread(() => { - while (_monitoring) // This "while" loop is basically the main loop of the monitor thread. + while (_ExplorerMonitorIsMonitoring) // This "while" loop is basically the main loop of the monitor thread. { try { - // Get the current explorer.exe process - Process[] explorerProcesses = Process.GetProcessesByName("explorer"); + // Get the desktop shell process ID. + uint shellProcessId = GetShellProcessId(); + + // Get the current processes with the retrieved executable name. + Process[] explorerProcesses = Process.GetProcessesByName(shellExecutableName); + + // Filter processes. + var validExplorerProcesses = explorerProcesses.Where(p => + { + try + { + string processPath = p.MainModule?.FileName; + + if (shellProcessId == 0) // We did not find shellProcessId, or we are using custom shell + { + return string.Equals(processPath, expectedShellPath, StringComparison.OrdinalIgnoreCase); + } + else // shellProcessId was found + { + return string.Equals(processPath, expectedShellPath, StringComparison.OrdinalIgnoreCase) && (uint)p.Id == shellProcessId; + } + } + catch + { + return false; // Skip inaccessible processes. + } + }).ToList(); + - if (explorerProcesses.Length == 0) // explorer.exe is not running + if (!validExplorerProcesses.Any()) // No valid processes found. { - // Only act if previously tracked explorer was running - if (Interlocked.CompareExchange(ref _lastExplorerPid, 0, 0) != -1) + // Only act if previously tracked Explorer was running. + if (Interlocked.CompareExchange(ref _ExplorerMonitorLastExplorerPid, 0, 0) != -1) { - // If we landed here, this might indicate that explorer is trying to start but failing, - // so we will restart RetroBar just in case RetroBar is crashing explorer. + // If we landed here, this might indicate that Explorer is trying to start but failing, + // or Explorer was closed manually, so we will restart RetroBar just in case RetroBar is causing a crash. RestartRetroBar(); } } - else // explorer.exe is running + else // Valid process was found. { - // Update current PID - int currentExplorerPid = explorerProcesses[0].Id; + Process desktopShellProcess = validExplorerProcesses.First(); - // Check if PID has changed - int lastExplorerPid = Interlocked.CompareExchange(ref _lastExplorerPid, 0, 0); + int currentExplorerPid = desktopShellProcess.Id; + + // Check if PID has changed. + int lastExplorerPid = Interlocked.CompareExchange(ref _ExplorerMonitorLastExplorerPid, 0, 0); if (lastExplorerPid != -1 && lastExplorerPid != currentExplorerPid) { - // Explorer PID was changed (explorer has restarted), so we will restart RetroBar. + // Explorer PID was changed (Explorer has restarted), so we will restart RetroBar. RestartRetroBar(); } - // Update the tracked PID - Interlocked.Exchange(ref _lastExplorerPid, currentExplorerPid); + // Update the tracked PID. + Interlocked.Exchange(ref _ExplorerMonitorLastExplorerPid, currentExplorerPid); } } catch (Exception ex) @@ -250,23 +286,109 @@ public void ExplorerMonitorStart() } // Sleep for a short interval to avoid excessive CPU usage. - // CPU usage was 0.00% with 500ms delay on test system. - // Increase _monitorUpdateDelay value to decrease CPU usage if needed. - // 500ms should be fine, unless your system is a potato. - // NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! - Thread.Sleep(_monitorUpdateDelay); + // CPU usage was 0.00% with 300ms delay on test systems. + // 300ms should be fine, unless your system is a potato. + // NOTE: You can increase _ExplorerMonitorUpdateDelay value to decrease CPU usage, + // but if this value is too high, Explorer will get stuck on a crash-restart-loop! + Thread.Sleep(_ExplorerMonitorUpdateDelay); } }); - _monitorThread.IsBackground = true; // Ensure our monitor thread exits when RetroBar is shutdown. - _monitorThread.Start(); + _ExplorerMonitorThread.IsBackground = true; // Ensure our monitor thread exits when RetroBar exits. + _ExplorerMonitorThread.Start(); + } + + private static string GetShellExecutableNameFromRegistry() + { + try + { + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")) + { + string shellValue = key?.GetValue("Shell") as string; + + if (!string.IsNullOrEmpty(shellValue)) + { + return System.IO.Path.GetFileNameWithoutExtension(shellValue); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error reading shell executable name from registry: {ex.Message}"); + } + + // Default to "explorer" if registry lookup fails. + return "explorer"; + } + + private static string GetShellPathFromRegistry() + { + try + { + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")) + { + // "Shell" key could either be explorer.exe or a custom shell path + string shellValue = key?.GetValue("Shell") as string; + + if (!string.IsNullOrEmpty(shellValue)) + { + // If the shell is "explorer.exe", construct its full path from the SystemRoot variable + if (shellValue.Equals("explorer.exe", StringComparison.OrdinalIgnoreCase)) + { + string systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); + if (!string.IsNullOrEmpty(systemRoot)) + { + return System.IO.Path.Combine(systemRoot, "explorer.exe"); + } + } + // If the shell is a custom executable, return the full path (if its already a full path) + else if (System.IO.Path.IsPathRooted(shellValue)) + { + return shellValue; // Return the custom shells full path + } + else + { + // If the shell value is a relative path, we could assume its in the SystemRoot directory + string systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); + if (!string.IsNullOrEmpty(systemRoot)) + { + return System.IO.Path.Combine(systemRoot, shellValue); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error reading shell path from registry: {ex.Message}"); + } + + // Fallback to default explorer.exe path if something goes wrong or no shell is found + return Environment.ExpandEnvironmentVariables(@"%SystemRoot%\explorer.exe"); + } + + private static uint GetShellProcessId() + { + // This is a call that is available on Windows 10 and 11. + // It will return the exact explorer process that is hosting the desktop shell, + // this ensures we dont accidentally target something like "File Explorer". + IntPtr shellWindowHandle = GetShellWindow(); + + if (shellWindowHandle == IntPtr.Zero) + { + Console.WriteLine("Shell window not found."); + return 0; + } + + GetWindowThreadProcessId(shellWindowHandle, out uint shellProcessId); + return shellProcessId; } private static void RestartRetroBar() { // RestartRetroBar function is called if we detect that explorer.exe PID has changed. - // Get RetroBar application path + // Get RetroBar application path. string appPath = Process.GetCurrentProcess().MainModule?.FileName; if (!string.IsNullOrEmpty(appPath)) @@ -275,8 +397,8 @@ private static void RestartRetroBar() { // Start a new instance before killing the current process. // There is a delay on RetroBar init so this is fine. - // NOTE: If the start delay of RetroBar is shortened or removed in the future, - // we will need to add a delay here. + // NOTE: If the start delay of RetroBar is decreased or removed in the future, + // we will need to add a delay before starting new RetroBar instance. Process.Start(appPath); } catch (Exception ex) From 32013df501cf8dca47cf873f0e9c4998ffabcfac Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:42:41 +0200 Subject: [PATCH 03/14] Replace "InteropServices" with "ManagedShell.Interop". --- RetroBar/Utilities/WindowManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 29afffd8..0392562a 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -1,11 +1,11 @@ using ManagedShell; using ManagedShell.AppBar; using ManagedShell.Common.Logging; +using ManagedShell.Interop; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; using Microsoft.Win32; @@ -27,8 +27,6 @@ public class WindowManager : IDisposable private volatile bool _ExplorerMonitorIsMonitoring; private Thread _ExplorerMonitorThread; private int _ExplorerMonitorLastExplorerPid = -1; - [DllImport("user32.dll")] private static extern IntPtr GetShellWindow(); - [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -372,7 +370,7 @@ private static uint GetShellProcessId() // This is a call that is available on Windows 10 and 11. // It will return the exact explorer process that is hosting the desktop shell, // this ensures we dont accidentally target something like "File Explorer". - IntPtr shellWindowHandle = GetShellWindow(); + IntPtr shellWindowHandle = NativeMethods.GetShellWindow(); if (shellWindowHandle == IntPtr.Zero) { @@ -380,7 +378,7 @@ private static uint GetShellProcessId() return 0; } - GetWindowThreadProcessId(shellWindowHandle, out uint shellProcessId); + NativeMethods.GetWindowThreadProcessId(shellWindowHandle, out uint shellProcessId); return shellProcessId; } From 0f0c0a883bd90fb031246d96671bb009a5393422 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:28:01 +0200 Subject: [PATCH 04/14] Use TaskbarCreated event to monitor Explorer restarts. --- RetroBar/Utilities/WindowManager.cs | 224 ++++++---------------------- 1 file changed, 44 insertions(+), 180 deletions(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 0392562a..c80075d2 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -1,14 +1,11 @@ using ManagedShell; using ManagedShell.AppBar; using ManagedShell.Common.Logging; -using ManagedShell.Interop; using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Threading; +using System.Runtime.InteropServices; using System.Windows.Forms; -using Microsoft.Win32; namespace RetroBar.Utilities { @@ -23,10 +20,9 @@ public class WindowManager : IDisposable private readonly ShellManager _shellManager; private readonly Updater _updater; - private readonly int _ExplorerMonitorUpdateDelay = 300; // Update delay in ms for explorer monitor thread. NOTE: If this value is too high, explorer.exe will get stuck on a restart loop! private volatile bool _ExplorerMonitorIsMonitoring; - private Thread _ExplorerMonitorThread; - private int _ExplorerMonitorLastExplorerPid = -1; + private ExplorerMonitor _ExplorerMonitor; + [DllImport("user32.dll", SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -195,217 +191,85 @@ private void resetScreenCache() public void Dispose() { + // Ensure that when WindowManager is disposed, the ExplorerMonitor is also disposed + if (_ExplorerMonitor != null){_ExplorerMonitor?.Dispose();} + _shellManager.ExplorerHelper.HideExplorerTaskbar = false; Settings.Instance.PropertyChanged -= Settings_PropertyChanged; } public void ExplorerMonitorStart() { - // Restarting RetroBar when Explorer is shutdown - // will allow Explorer to initialize properly, - // this fixes crash-restart-loop bug. - - // Prevent multiple monitor threads. - if(_ExplorerMonitorIsMonitoring){return;} - - _ExplorerMonitorIsMonitoring = true; // Set flag to true, to prevent multiple monitor threads. - - // Get the expected shell (Explorer) executable name and path from the registry. - string shellExecutableName = GetShellExecutableNameFromRegistry(); - string expectedShellPath = GetShellPathFromRegistry(); - - // Start monitor thread. - _ExplorerMonitorThread = new Thread(() => + if(_ExplorerMonitorIsMonitoring) // Prevent multiple monitors. { - while (_ExplorerMonitorIsMonitoring) // This "while" loop is basically the main loop of the monitor thread. - { - try - { - // Get the desktop shell process ID. - uint shellProcessId = GetShellProcessId(); - - // Get the current processes with the retrieved executable name. - Process[] explorerProcesses = Process.GetProcessesByName(shellExecutableName); - - // Filter processes. - var validExplorerProcesses = explorerProcesses.Where(p => - { - try - { - string processPath = p.MainModule?.FileName; - - if (shellProcessId == 0) // We did not find shellProcessId, or we are using custom shell - { - return string.Equals(processPath, expectedShellPath, StringComparison.OrdinalIgnoreCase); - } - else // shellProcessId was found - { - return string.Equals(processPath, expectedShellPath, StringComparison.OrdinalIgnoreCase) && (uint)p.Id == shellProcessId; - } - } - catch - { - return false; // Skip inaccessible processes. - } - }).ToList(); - - - if (!validExplorerProcesses.Any()) // No valid processes found. - { - // Only act if previously tracked Explorer was running. - if (Interlocked.CompareExchange(ref _ExplorerMonitorLastExplorerPid, 0, 0) != -1) - { - // If we landed here, this might indicate that Explorer is trying to start but failing, - // or Explorer was closed manually, so we will restart RetroBar just in case RetroBar is causing a crash. - RestartRetroBar(); - } - } - else // Valid process was found. - { - Process desktopShellProcess = validExplorerProcesses.First(); - - int currentExplorerPid = desktopShellProcess.Id; - - // Check if PID has changed. - int lastExplorerPid = Interlocked.CompareExchange(ref _ExplorerMonitorLastExplorerPid, 0, 0); - if (lastExplorerPid != -1 && lastExplorerPid != currentExplorerPid) - { - // Explorer PID was changed (Explorer has restarted), so we will restart RetroBar. - RestartRetroBar(); - } - - // Update the tracked PID. - Interlocked.Exchange(ref _ExplorerMonitorLastExplorerPid, currentExplorerPid); - } - } - catch (Exception ex) - { - Console.WriteLine($"Error monitoring explorer.exe: {ex.Message}"); - } - - // Sleep for a short interval to avoid excessive CPU usage. - // CPU usage was 0.00% with 300ms delay on test systems. - // 300ms should be fine, unless your system is a potato. - // NOTE: You can increase _ExplorerMonitorUpdateDelay value to decrease CPU usage, - // but if this value is too high, Explorer will get stuck on a crash-restart-loop! - Thread.Sleep(_ExplorerMonitorUpdateDelay); - } - }); + return; + } + else + { + _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. - _ExplorerMonitorThread.IsBackground = true; // Ensure our monitor thread exits when RetroBar exits. - _ExplorerMonitorThread.Start(); + // Start monitoring + _ExplorerMonitor = new ExplorerMonitor(this); + _ExplorerMonitor.Show(); + } } - private static string GetShellExecutableNameFromRegistry() + // ExplorerMonitor is a hidden form that captures taskbar events + public class ExplorerMonitor : Form { - try - { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")) - { - string shellValue = key?.GetValue("Shell") as string; + private readonly WindowManager _windowManager; - if (!string.IsNullOrEmpty(shellValue)) - { - return System.IO.Path.GetFileNameWithoutExtension(shellValue); - } - } - } - catch (Exception ex) + public ExplorerMonitor(WindowManager windowManager) { - Console.WriteLine($"Error reading shell executable name from registry: {ex.Message}"); + _windowManager = windowManager; // This is for the callback + + // These will make the ExplorerMonitor form completely invisible, so we can use it just as a monitor and not form + ClientSize = new System.Drawing.Size(1, 1); // Set the size to 1x1 pixel (tiny and invisible) + FormBorderStyle = FormBorderStyle.None; // Make the form borderless + BackColor = System.Drawing.Color.Lime; // Use a color thats fully transparent in the form + TransparencyKey = System.Drawing.Color.Lime; // Set transparency key to make the color transparent + ShowInTaskbar = false; // Ensure the form doesnt appear in the taskbar + ControlBox = false; // Ensure no controls (like buttons) are on the form + Visible = false; // Set the form as invisible + StartPosition = FormStartPosition.Manual; // Dont center this form + Location = new System.Drawing.Point(-1000, -1000); // Move it far off-screen } - // Default to "explorer" if registry lookup fails. - return "explorer"; - } - - private static string GetShellPathFromRegistry() - { - try + // We will override WndProc to listen for TaskbarCreated event + protected override void WndProc(ref Message m) { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")) + if (m.Msg == (int)RegisterWindowMessage("TaskbarCreated")) { - // "Shell" key could either be explorer.exe or a custom shell path - string shellValue = key?.GetValue("Shell") as string; - - if (!string.IsNullOrEmpty(shellValue)) - { - // If the shell is "explorer.exe", construct its full path from the SystemRoot variable - if (shellValue.Equals("explorer.exe", StringComparison.OrdinalIgnoreCase)) - { - string systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); - if (!string.IsNullOrEmpty(systemRoot)) - { - return System.IO.Path.Combine(systemRoot, "explorer.exe"); - } - } - // If the shell is a custom executable, return the full path (if its already a full path) - else if (System.IO.Path.IsPathRooted(shellValue)) - { - return shellValue; // Return the custom shells full path - } - else - { - // If the shell value is a relative path, we could assume its in the SystemRoot directory - string systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); - if (!string.IsNullOrEmpty(systemRoot)) - { - return System.IO.Path.Combine(systemRoot, shellValue); - } - } - } + _windowManager.OnTaskbarCreated(); // Handle TaskbarCreated event } - } - catch (Exception ex) - { - Console.WriteLine($"Error reading shell path from registry: {ex.Message}"); - } - // Fallback to default explorer.exe path if something goes wrong or no shell is found - return Environment.ExpandEnvironmentVariables(@"%SystemRoot%\explorer.exe"); + base.WndProc(ref m); // Call the base class to process other messages so we dont accidentally cause crashes or bugs. + } } - private static uint GetShellProcessId() + // Callback for TaskbarCreated event + internal void OnTaskbarCreated() { - // This is a call that is available on Windows 10 and 11. - // It will return the exact explorer process that is hosting the desktop shell, - // this ensures we dont accidentally target something like "File Explorer". - IntPtr shellWindowHandle = NativeMethods.GetShellWindow(); - - if (shellWindowHandle == IntPtr.Zero) - { - Console.WriteLine("Shell window not found."); - return 0; - } - - NativeMethods.GetWindowThreadProcessId(shellWindowHandle, out uint shellProcessId); - return shellProcessId; + // If TaskbarCreated event is detected, restart RetroBar for proper re-initializing. + RestartRetroBar(); } private static void RestartRetroBar() { - // RestartRetroBar function is called if we detect that explorer.exe PID has changed. - - // Get RetroBar application path. string appPath = Process.GetCurrentProcess().MainModule?.FileName; if (!string.IsNullOrEmpty(appPath)) { try { - // Start a new instance before killing the current process. - // There is a delay on RetroBar init so this is fine. - // NOTE: If the start delay of RetroBar is decreased or removed in the future, - // we will need to add a delay before starting new RetroBar instance. - Process.Start(appPath); + Process.Start(appPath); // Start a new instance } catch (Exception ex) { Console.WriteLine($"Error restarting RetroBar: {ex.Message}"); } - // Exit current RetroBar process. - Environment.Exit(0); + Environment.Exit(0); // Exit the current instance } else { From 3e99e7ff5565ee38e469cccdedfda70b40217957 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:54:13 +0200 Subject: [PATCH 05/14] Remove ExplorerMonitor from the Alt+Tab list. --- RetroBar/Utilities/WindowManager.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index c80075d2..1a6e2f7a 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -23,6 +23,8 @@ public class WindowManager : IDisposable private volatile bool _ExplorerMonitorIsMonitoring; private ExplorerMonitor _ExplorerMonitor; [DllImport("user32.dll", SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); + [DllImport("user32.dll")] private static extern IntPtr SetWindowLong(IntPtr hwnd, int index, int newStyle); + [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hwnd, int index); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -218,6 +220,9 @@ public void ExplorerMonitorStart() public class ExplorerMonitor : Form { private readonly WindowManager _windowManager; + private const int GWL_EXSTYLE = -20; + private const int WS_EX_TOOLWINDOW = 0x00000080; + private const int WS_EX_APPWINDOW = 0x00040000; public ExplorerMonitor(WindowManager windowManager) { @@ -233,6 +238,10 @@ public ExplorerMonitor(WindowManager windowManager) Visible = false; // Set the form as invisible StartPosition = FormStartPosition.Manual; // Dont center this form Location = new System.Drawing.Point(-1000, -1000); // Move it far off-screen + + // Remove ExplorerMonitor from the Alt+Tab list by modifying its extended style + var extendedStyle = GetWindowLong(this.Handle, GWL_EXSTYLE); + SetWindowLong(this.Handle, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW); } // We will override WndProc to listen for TaskbarCreated event From 503fcb567e7116a6e56e5c28df1b92644aa2d5f4 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:55:04 +0200 Subject: [PATCH 06/14] Move ExplorerMonitor to ExplorerMonitor.cs and simplify code. --- RetroBar/Utilities/ExplorerMonitor.cs | 85 +++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 RetroBar/Utilities/ExplorerMonitor.cs diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs new file mode 100644 index 00000000..224060cc --- /dev/null +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace RetroBar.Utilities +{ + public class ExplorerMonitor : IDisposable + { + private volatile bool _ExplorerMonitorIsMonitoring; + private _ExplorerMonitor _explorerMonitor; + + public void ExplorerMonitorStart() + { + if(_ExplorerMonitorIsMonitoring) // Prevent multiple monitors. + { + return; + } + else + { + _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. + + // Start monitoring + _explorerMonitor = new _ExplorerMonitor(); + _explorerMonitor.Show(); + } + } + + // ExplorerMonitor is a hidden form that captures taskbar events + private class _ExplorerMonitor : Form + { + private const int GWL_EXSTYLE = -20; + private const int WS_EX_TOOLWINDOW = 0x00000080; + private const int WS_EX_APPWINDOW = 0x00040000; + + [DllImport("user32.dll", SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); + [DllImport("user32.dll")] private static extern IntPtr SetWindowLong(IntPtr hwnd, int index, int newStyle); + [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hwnd, int index); + + public _ExplorerMonitor() + { + // These will make the ExplorerMonitor form completely invisible, so we can use it just as a monitor and not form + ClientSize = new System.Drawing.Size(1, 1); // Set the size to 1x1 pixel (tiny and invisible) + FormBorderStyle = FormBorderStyle.None; // Make the form borderless + BackColor = System.Drawing.Color.Lime; // Use a color thats fully transparent in the form + TransparencyKey = System.Drawing.Color.Lime; // Set transparency key to make the color transparent + ShowInTaskbar = false; // Ensure the form doesnt appear in the taskbar + ControlBox = false; // Ensure no controls (like buttons) are on the form + Visible = false; // Set the form as invisible + StartPosition = FormStartPosition.Manual; // Dont center this form + Location = new System.Drawing.Point(-1000, -1000); // Move it far off-screen + + // Remove ExplorerMonitor from the Alt+Tab list by modifying its extended style + int extendedStyle = GetWindowLong(this.Handle, GWL_EXSTYLE); + SetWindowLong(this.Handle, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW); + } + + // We will override WndProc to listen for TaskbarCreated event + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)RegisterWindowMessage("TaskbarCreated")) + { + try + { + string appPath = Process.GetCurrentProcess().MainModule?.FileName; + Process.Start(appPath); // Start a new instance of RetroBar + Environment.Exit(0); // Exit the current instance of RetroBar + } + catch (Exception ex) + { + Console.WriteLine($"Error restarting RetroBar: {ex.Message}"); + } + } + + // Call the base class to process other messages so we dont accidentally cause crashes or bugs. + base.WndProc(ref m); + } + } + + public void Dispose() + { + if (_explorerMonitor != null){_explorerMonitor?.Dispose();} + } + } +} From 6d6547a5f0895eacd4de3ce80cd6167c55856df4 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:55:34 +0200 Subject: [PATCH 07/14] Move ExplorerMonitor to ExplorerMonitor.cs and simplify code. --- RetroBar/Utilities/WindowManager.cs | 100 +--------------------------- 1 file changed, 3 insertions(+), 97 deletions(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 1a6e2f7a..67f263e3 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -3,8 +3,6 @@ using ManagedShell.Common.Logging; using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; using System.Windows.Forms; namespace RetroBar.Utilities @@ -20,11 +18,7 @@ public class WindowManager : IDisposable private readonly ShellManager _shellManager; private readonly Updater _updater; - private volatile bool _ExplorerMonitorIsMonitoring; - private ExplorerMonitor _ExplorerMonitor; - [DllImport("user32.dll", SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); - [DllImport("user32.dll")] private static extern IntPtr SetWindowLong(IntPtr hwnd, int index, int newStyle); - [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hwnd, int index); + private readonly ExplorerMonitor _explorerMonitor = new ExplorerMonitor(); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -32,7 +26,7 @@ public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonito _startMenuMonitor = startMenuMonitor; _updater = updater; - ExplorerMonitorStart(); + _explorerMonitor.ExplorerMonitorStart(); _shellManager.ExplorerHelper.HideExplorerTaskbar = true; @@ -193,97 +187,9 @@ private void resetScreenCache() public void Dispose() { - // Ensure that when WindowManager is disposed, the ExplorerMonitor is also disposed - if (_ExplorerMonitor != null){_ExplorerMonitor?.Dispose();} - + if (_explorerMonitor != null){_explorerMonitor?.Dispose();} _shellManager.ExplorerHelper.HideExplorerTaskbar = false; Settings.Instance.PropertyChanged -= Settings_PropertyChanged; } - - public void ExplorerMonitorStart() - { - if(_ExplorerMonitorIsMonitoring) // Prevent multiple monitors. - { - return; - } - else - { - _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. - - // Start monitoring - _ExplorerMonitor = new ExplorerMonitor(this); - _ExplorerMonitor.Show(); - } - } - - // ExplorerMonitor is a hidden form that captures taskbar events - public class ExplorerMonitor : Form - { - private readonly WindowManager _windowManager; - private const int GWL_EXSTYLE = -20; - private const int WS_EX_TOOLWINDOW = 0x00000080; - private const int WS_EX_APPWINDOW = 0x00040000; - - public ExplorerMonitor(WindowManager windowManager) - { - _windowManager = windowManager; // This is for the callback - - // These will make the ExplorerMonitor form completely invisible, so we can use it just as a monitor and not form - ClientSize = new System.Drawing.Size(1, 1); // Set the size to 1x1 pixel (tiny and invisible) - FormBorderStyle = FormBorderStyle.None; // Make the form borderless - BackColor = System.Drawing.Color.Lime; // Use a color thats fully transparent in the form - TransparencyKey = System.Drawing.Color.Lime; // Set transparency key to make the color transparent - ShowInTaskbar = false; // Ensure the form doesnt appear in the taskbar - ControlBox = false; // Ensure no controls (like buttons) are on the form - Visible = false; // Set the form as invisible - StartPosition = FormStartPosition.Manual; // Dont center this form - Location = new System.Drawing.Point(-1000, -1000); // Move it far off-screen - - // Remove ExplorerMonitor from the Alt+Tab list by modifying its extended style - var extendedStyle = GetWindowLong(this.Handle, GWL_EXSTYLE); - SetWindowLong(this.Handle, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW); - } - - // We will override WndProc to listen for TaskbarCreated event - protected override void WndProc(ref Message m) - { - if (m.Msg == (int)RegisterWindowMessage("TaskbarCreated")) - { - _windowManager.OnTaskbarCreated(); // Handle TaskbarCreated event - } - - base.WndProc(ref m); // Call the base class to process other messages so we dont accidentally cause crashes or bugs. - } - } - - // Callback for TaskbarCreated event - internal void OnTaskbarCreated() - { - // If TaskbarCreated event is detected, restart RetroBar for proper re-initializing. - RestartRetroBar(); - } - - private static void RestartRetroBar() - { - string appPath = Process.GetCurrentProcess().MainModule?.FileName; - - if (!string.IsNullOrEmpty(appPath)) - { - try - { - Process.Start(appPath); // Start a new instance - } - catch (Exception ex) - { - Console.WriteLine($"Error restarting RetroBar: {ex.Message}"); - } - - Environment.Exit(0); // Exit the current instance - } - else - { - throw new InvalidOperationException("Unable to determine the path of RetroBar."); - } - } } } From 6d98ce511b7a7da68c6b50fea9334cdaad4fe748 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:29:47 +0200 Subject: [PATCH 08/14] Replace Form with NativeWindow. --- RetroBar/Utilities/ExplorerMonitor.cs | 59 ++++++++++----------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs index 224060cc..ad91af88 100644 --- a/RetroBar/Utilities/ExplorerMonitor.cs +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -1,14 +1,14 @@ +using ManagedShell.Interop; using System; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Windows.Forms; namespace RetroBar.Utilities { public class ExplorerMonitor : IDisposable { - private volatile bool _ExplorerMonitorIsMonitoring; - private _ExplorerMonitor _explorerMonitor; + private bool _ExplorerMonitorIsMonitoring; + private MonitorWindow _explorerMonitor; public void ExplorerMonitorStart() { @@ -19,67 +19,52 @@ public void ExplorerMonitorStart() else { _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. - - // Start monitoring - _explorerMonitor = new _ExplorerMonitor(); - _explorerMonitor.Show(); + _explorerMonitor = new MonitorWindow(); // Start monitoring. } } - // ExplorerMonitor is a hidden form that captures taskbar events - private class _ExplorerMonitor : Form + public void Dispose() { - private const int GWL_EXSTYLE = -20; - private const int WS_EX_TOOLWINDOW = 0x00000080; - private const int WS_EX_APPWINDOW = 0x00040000; + if (_explorerMonitor != null){_explorerMonitor?.Dispose();} + } - [DllImport("user32.dll", SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); - [DllImport("user32.dll")] private static extern IntPtr SetWindowLong(IntPtr hwnd, int index, int newStyle); - [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hwnd, int index); + // NativeWindow implementation for monitoring + private class MonitorWindow : NativeWindow, IDisposable + { + //private readonly WindowManager _windowManager; + private static readonly int TaskbarCreatedMessage = NativeMethods.RegisterWindowMessage("TaskbarCreated"); - public _ExplorerMonitor() + public MonitorWindow() { - // These will make the ExplorerMonitor form completely invisible, so we can use it just as a monitor and not form - ClientSize = new System.Drawing.Size(1, 1); // Set the size to 1x1 pixel (tiny and invisible) - FormBorderStyle = FormBorderStyle.None; // Make the form borderless - BackColor = System.Drawing.Color.Lime; // Use a color thats fully transparent in the form - TransparencyKey = System.Drawing.Color.Lime; // Set transparency key to make the color transparent - ShowInTaskbar = false; // Ensure the form doesnt appear in the taskbar - ControlBox = false; // Ensure no controls (like buttons) are on the form - Visible = false; // Set the form as invisible - StartPosition = FormStartPosition.Manual; // Dont center this form - Location = new System.Drawing.Point(-1000, -1000); // Move it far off-screen - - // Remove ExplorerMonitor from the Alt+Tab list by modifying its extended style - int extendedStyle = GetWindowLong(this.Handle, GWL_EXSTYLE); - SetWindowLong(this.Handle, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW); + CreateHandle(new CreateParams()); } - // We will override WndProc to listen for TaskbarCreated event protected override void WndProc(ref Message m) { - if (m.Msg == (int)RegisterWindowMessage("TaskbarCreated")) + if (m.Msg == TaskbarCreatedMessage) { try { + //_windowManager.ReopenTaskbars(); // Reopen taskbars if explorer.exe is restarted. string appPath = Process.GetCurrentProcess().MainModule?.FileName; Process.Start(appPath); // Start a new instance of RetroBar Environment.Exit(0); // Exit the current instance of RetroBar } catch (Exception ex) { - Console.WriteLine($"Error restarting RetroBar: {ex.Message}"); + //Debug.WriteLine($"Error handling TaskbarCreated message on ExplorerMonitor: {ex.Message}"); + Debug.WriteLine($"Error restarting RetroBar: {ex.Message}"); } } // Call the base class to process other messages so we dont accidentally cause crashes or bugs. base.WndProc(ref m); } - } - public void Dispose() - { - if (_explorerMonitor != null){_explorerMonitor?.Dispose();} + public void Dispose() + { + DestroyHandle(); + } } } } From c00a39ae030c8372d3576884015d193b0e05bab8 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:14:45 +0200 Subject: [PATCH 09/14] Call ReopenTaskbars instead of complete restart. --- RetroBar/Utilities/WindowManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 67f263e3..49d784f6 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -26,7 +26,7 @@ public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonito _startMenuMonitor = startMenuMonitor; _updater = updater; - _explorerMonitor.ExplorerMonitorStart(); + _explorerMonitor.ExplorerMonitorStart(this); _shellManager.ExplorerHelper.HideExplorerTaskbar = true; From bc158a5c1dbcb7d089028900c8af22d615660b74 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:15:10 +0200 Subject: [PATCH 10/14] Call ReopenTaskbars instead of complete restart. --- RetroBar/Utilities/ExplorerMonitor.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs index ad91af88..15d80173 100644 --- a/RetroBar/Utilities/ExplorerMonitor.cs +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -10,7 +10,7 @@ public class ExplorerMonitor : IDisposable private bool _ExplorerMonitorIsMonitoring; private MonitorWindow _explorerMonitor; - public void ExplorerMonitorStart() + public void ExplorerMonitorStart(WindowManager _windowManagerReference) { if(_ExplorerMonitorIsMonitoring) // Prevent multiple monitors. { @@ -19,7 +19,7 @@ public void ExplorerMonitorStart() else { _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. - _explorerMonitor = new MonitorWindow(); // Start monitoring. + _explorerMonitor = new MonitorWindow(_windowManagerReference); // Start monitoring. } } @@ -31,11 +31,12 @@ public void Dispose() // NativeWindow implementation for monitoring private class MonitorWindow : NativeWindow, IDisposable { - //private readonly WindowManager _windowManager; + private WindowManager _windowManager; private static readonly int TaskbarCreatedMessage = NativeMethods.RegisterWindowMessage("TaskbarCreated"); - public MonitorWindow() + public MonitorWindow(WindowManager _windowManagerReference) { + _windowManager = _windowManagerReference; CreateHandle(new CreateParams()); } @@ -45,15 +46,11 @@ protected override void WndProc(ref Message m) { try { - //_windowManager.ReopenTaskbars(); // Reopen taskbars if explorer.exe is restarted. - string appPath = Process.GetCurrentProcess().MainModule?.FileName; - Process.Start(appPath); // Start a new instance of RetroBar - Environment.Exit(0); // Exit the current instance of RetroBar + _windowManager.ReopenTaskbars(); // Reopen taskbars if explorer.exe is restarted. } catch (Exception ex) { - //Debug.WriteLine($"Error handling TaskbarCreated message on ExplorerMonitor: {ex.Message}"); - Debug.WriteLine($"Error restarting RetroBar: {ex.Message}"); + Debug.WriteLine($"Error handling TaskbarCreated message on ExplorerMonitor: {ex.Message}"); } } From a9f44cd46b434154f4070a6283e766ac7e567ffd Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:30:17 +0200 Subject: [PATCH 11/14] Clean code. --- RetroBar/Utilities/WindowManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RetroBar/Utilities/WindowManager.cs b/RetroBar/Utilities/WindowManager.cs index 49d784f6..90215133 100644 --- a/RetroBar/Utilities/WindowManager.cs +++ b/RetroBar/Utilities/WindowManager.cs @@ -18,7 +18,7 @@ public class WindowManager : IDisposable private readonly ShellManager _shellManager; private readonly Updater _updater; - private readonly ExplorerMonitor _explorerMonitor = new ExplorerMonitor(); + private readonly ExplorerMonitor _explorerMonitor = new(); public WindowManager(ShellManager shellManager, StartMenuMonitor startMenuMonitor, Updater updater) { @@ -187,7 +187,7 @@ private void resetScreenCache() public void Dispose() { - if (_explorerMonitor != null){_explorerMonitor?.Dispose();} + _explorerMonitor?.Dispose(); _shellManager.ExplorerHelper.HideExplorerTaskbar = false; Settings.Instance.PropertyChanged -= Settings_PropertyChanged; } From 1194ef321ede03bb3bcff488224e3d127d32531c Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:31:03 +0200 Subject: [PATCH 12/14] Clean code and some minor changes to match existing project code. --- RetroBar/Utilities/ExplorerMonitor.cs | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs index 15d80173..0a9f7b09 100644 --- a/RetroBar/Utilities/ExplorerMonitor.cs +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -7,46 +7,40 @@ namespace RetroBar.Utilities { public class ExplorerMonitor : IDisposable { - private bool _ExplorerMonitorIsMonitoring; - private MonitorWindow _explorerMonitor; + private bool _explorerMonitorisMonitoring; + private ExplorerMonitorWindow _explorerMonitorWindow; - public void ExplorerMonitorStart(WindowManager _windowManagerReference) + public void ExplorerMonitorStart(WindowManager windowManagerRef) { - if(_ExplorerMonitorIsMonitoring) // Prevent multiple monitors. - { - return; - } - else - { - _ExplorerMonitorIsMonitoring = true; // We will set flag to true to prevent multiple monitors. - _explorerMonitor = new MonitorWindow(_windowManagerReference); // Start monitoring. - } + if (_explorerMonitorisMonitoring) { return; } // Prevent multiple monitors. + + _explorerMonitorisMonitoring = true; + _explorerMonitorWindow = new ExplorerMonitorWindow(windowManagerRef); // Start monitoring. } public void Dispose() { - if (_explorerMonitor != null){_explorerMonitor?.Dispose();} + _explorerMonitorWindow?.Dispose(); } - // NativeWindow implementation for monitoring - private class MonitorWindow : NativeWindow, IDisposable + private class ExplorerMonitorWindow : NativeWindow, IDisposable { - private WindowManager _windowManager; - private static readonly int TaskbarCreatedMessage = NativeMethods.RegisterWindowMessage("TaskbarCreated"); + private readonly WindowManager _windowManagerRef; + private static readonly int WM_TASKBARCREATEDMESSAGE = NativeMethods.RegisterWindowMessage("TaskbarCreated"); - public MonitorWindow(WindowManager _windowManagerReference) + public ExplorerMonitorWindow(WindowManager windowManager) { - _windowManager = _windowManagerReference; + _windowManagerRef = windowManager; CreateHandle(new CreateParams()); } protected override void WndProc(ref Message m) { - if (m.Msg == TaskbarCreatedMessage) + if (m.Msg == WM_TASKBARCREATEDMESSAGE) { try { - _windowManager.ReopenTaskbars(); // Reopen taskbars if explorer.exe is restarted. + _windowManagerRef.ReopenTaskbars(); } catch (Exception ex) { @@ -54,7 +48,6 @@ protected override void WndProc(ref Message m) } } - // Call the base class to process other messages so we dont accidentally cause crashes or bugs. base.WndProc(ref m); } From fc3ccd5fadfea9c85398a9e788b6a8f70efa4194 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:36:55 +0200 Subject: [PATCH 13/14] Add comments... --- RetroBar/Utilities/ExplorerMonitor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs index 0a9f7b09..81602e68 100644 --- a/RetroBar/Utilities/ExplorerMonitor.cs +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -40,7 +40,7 @@ protected override void WndProc(ref Message m) { try { - _windowManagerRef.ReopenTaskbars(); + _windowManagerRef.ReopenTaskbars(); // Reopen taskbars if explorer.exe is restarted. } catch (Exception ex) { @@ -48,7 +48,7 @@ protected override void WndProc(ref Message m) } } - base.WndProc(ref m); + base.WndProc(ref m); // Call the base class to process other messages so we dont accidentally cause crashes or bugs. } public void Dispose() From e5363b28726ecbe73660832002aa4150e5f82ba7 Mon Sep 17 00:00:00 2001 From: MKKNinetyTwo <152527792+MKKNinetyTwo@users.noreply.github.com> Date: Fri, 15 Nov 2024 04:45:05 +0200 Subject: [PATCH 14/14] Minor refactorings. --- RetroBar/Utilities/ExplorerMonitor.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/RetroBar/Utilities/ExplorerMonitor.cs b/RetroBar/Utilities/ExplorerMonitor.cs index 81602e68..bb9ed46c 100644 --- a/RetroBar/Utilities/ExplorerMonitor.cs +++ b/RetroBar/Utilities/ExplorerMonitor.cs @@ -1,20 +1,18 @@ +using ManagedShell.Common.Logging; using ManagedShell.Interop; using System; -using System.Diagnostics; using System.Windows.Forms; namespace RetroBar.Utilities { public class ExplorerMonitor : IDisposable { - private bool _explorerMonitorisMonitoring; private ExplorerMonitorWindow _explorerMonitorWindow; public void ExplorerMonitorStart(WindowManager windowManagerRef) { - if (_explorerMonitorisMonitoring) { return; } // Prevent multiple monitors. + if (_explorerMonitorWindow != null) { return; } // Prevent multiple monitors. - _explorerMonitorisMonitoring = true; _explorerMonitorWindow = new ExplorerMonitorWindow(windowManagerRef); // Start monitoring. } @@ -28,9 +26,9 @@ private class ExplorerMonitorWindow : NativeWindow, IDisposable private readonly WindowManager _windowManagerRef; private static readonly int WM_TASKBARCREATEDMESSAGE = NativeMethods.RegisterWindowMessage("TaskbarCreated"); - public ExplorerMonitorWindow(WindowManager windowManager) + public ExplorerMonitorWindow(WindowManager windowManagerRef) { - _windowManagerRef = windowManager; + _windowManagerRef = windowManagerRef; CreateHandle(new CreateParams()); } @@ -44,7 +42,7 @@ protected override void WndProc(ref Message m) } catch (Exception ex) { - Debug.WriteLine($"Error handling TaskbarCreated message on ExplorerMonitor: {ex.Message}"); + ShellLogger.Warning($"Error handling TaskbarCreated message on ExplorerMonitor: {ex.Message}"); } }