From b012a1397f5a523fcb78381fc0dd56701a5b60f6 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:37:21 -0400 Subject: [PATCH] Bring existing window to foreground on second launch instead of error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lite: Replace "already running" error dialog with FindWindow/ SetForegroundWindow to activate the existing instance. Only call SW_RESTORE if the window is minimized (IsIconic) to preserve maximized state. Dashboard: Fix WndProc handler to only reset WindowState when minimized, preserving maximized state on second-launch activation. Both: Keep minimize-to-tray as a user setting — when enabled, the window hides from the taskbar on minimize (restored via tray icon). Fixes #769 Co-Authored-By: Claude Opus 4.6 (1M context) --- Dashboard/MainWindow.xaml.cs | 5 +++-- Lite/App.xaml.cs | 28 +++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Dashboard/MainWindow.xaml.cs b/Dashboard/MainWindow.xaml.cs index 151d218b..396e8ebb 100644 --- a/Dashboard/MainWindow.xaml.cs +++ b/Dashboard/MainWindow.xaml.cs @@ -137,9 +137,10 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b { if (msg == NativeMethods.WM_SHOWMONITOR) { - // Another instance tried to start - bring this window to front + // Another instance tried to start - bring this window to front (#769) Show(); - WindowState = WindowState.Normal; + if (WindowState == WindowState.Minimized) + WindowState = WindowState.Normal; Activate(); Topmost = true; // Temporarily set topmost to ensure visibility Topmost = false; diff --git a/Lite/App.xaml.cs b/Lite/App.xaml.cs index d4443041..4b2ba29b 100644 --- a/Lite/App.xaml.cs +++ b/Lite/App.xaml.cs @@ -22,6 +22,21 @@ public partial class App : Application [DllImport("shell32.dll", SetLastError = true)] private static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string appId); + [DllImport("user32.dll")] + private static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + private static extern IntPtr FindWindow(string? lpClassName, string lpWindowName); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool IsIconic(IntPtr hWnd); + + private const int SW_RESTORE = 9; + private const string MutexName = "PerformanceMonitorLite_SingleInstance"; private Mutex? _singleInstanceMutex; private bool _ownsMutex; @@ -167,11 +182,14 @@ protected override void OnStartup(StartupEventArgs e) if (!_ownsMutex) { - MessageBox.Show( - "Performance Monitor Lite is already running.", - "Already Running", - MessageBoxButton.OK, - MessageBoxImage.Information); + /* Bring the existing instance's window to the foreground instead of showing an error (#769) */ + var hWnd = FindWindow(null, "Performance Monitor Lite"); + if (hWnd != IntPtr.Zero) + { + if (IsIconic(hWnd)) + ShowWindow(hWnd, SW_RESTORE); + SetForegroundWindow(hWnd); + } Shutdown(); return; }