/ Published in: C#
This snippet is based on [jimfred's snippet](http://snipplr.com/view/19272/ "ingle-instance-check using mutex. Implements a static function to be called in Program::Main()."). Second instance of application shows MainWindow of the previous one instance of application, even if it has become invisible.
This is may be usefull when the very first instance sits in the tray and hides their own MainWindow.
This is may be usefull when the very first instance sits in the tray and hides their own MainWindow.
Expand |
Embed | Plain Text
Copy this code and paste it in your HTML
namespace Utils { /// <summary> /// This checks for another instance of an app. /// Use inside Main() by calling SingleInstanceCheck.Check(); /// Include this class as a sibling to Main's class. /// If another instance of the app is detected, /// - MainWindow of the first instance appears. /// - 'this' instance calls Exit. /// </summary> /// <example> /// static void Main() /// { /// SingleInstanceCheck.Check(); /// Application.EnableVisualStyles(); /// Application.SetCompatibleTextRenderingDefault(false); /// Application.Run(new Form1()); /// } /// </example> public static class SingleInstanceCheck { static bool FindInvisibleWindow(IntPtr hWnd, IntPtr lParam) { // skip visible windows if (SafeNativeMethods.IsWindowVisible(wndRef)) return true; // skip windows without caption if (SafeNativeMethods.GetWindowTextLength(wndRef) == 0) return true; // retrieve process id for a window int ProcID; SafeNativeMethods.GetWindowThreadProcessId(wndRef, out ProcID); // we found or not if (ProcID == lParam.ToInt32()) { UnsafeNativeMethods.ShowWindowAsync(wndRef, NativeMethods.SW_NORMAL); UnsafeNativeMethods.SetForegroundWindow(wndRef); return false; } return true; } static public void Check() { bool isOwnedHere = false; true, Application.ProductName, out isOwnedHere ); if (isOwnedHere) return; Process me = Process.GetCurrentProcess(); foreach (Process process in Process.GetProcessesByName(me.ProcessName)) // Debug note: Set Enable the Visual Studio Hosting Process = false. { if (process.Id != me.Id) // If the ProcessName matches but the Id doesn't, it's another instance of mine. { if (process.MainWindowHandle != IntPtr.Zero) { UnsafeNativeMethods.ShowWindowAsync(wndRef, NativeMethods.SW_NORMAL); UnsafeNativeMethods.SetForegroundWindow(wndRef); } else { GC.KeepAlive(callback); } break; } } Environment.Exit(0); // This will kill my instance. } // volatile is intended to prevent GC. Otherwise, GC.KeepAlive(appStartMutex) might be needed. // This appears to be a concern in In release builds but not debug builds. static volatile Mutex appStartMutex; } internal static class NativeMethods { public const int SW_HIDE = 0, SW_NORMAL = 1, SW_SHOWMINIMIZED = 2, SW_SHOWMAXIMIZED = 3, SW_MAXIMIZE = 3, SW_SHOWNOACTIVATE = 4, SW_SHOW = 5, SW_MINIMIZE = 6, SW_SHOWMINNOACTIVE = 7, SW_SHOWNA = 8, SW_RESTORE = 9, SW_MAX = 10, SWP_NOSIZE = 0x0001, SWP_NOMOVE = 0x0002, SWP_NOZORDER = 0x0004, SWP_NOACTIVATE = 0x0010, SWP_SHOWWINDOW = 0x0040, SWP_HIDEWINDOW = 0x0080, SWP_DRAWFRAME = 0x0020, SWP_NOOWNERZORDER = 0x0200; } internal class ExternDll { private ExternDll() { } internal const string User32 = "user32.dll"; } [SuppressUnmanagedCodeSecurity] internal static class UnsafeNativeMethods { [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern bool SetForegroundWindow(HandleRef hWnd); /// <SecurityNote> /// Critical: This elevates to unmanaged code permission /// </SecurityNote> [SecurityCritical, SuppressUnmanagedCodeSecurity] [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow); } [SuppressUnmanagedCodeSecurity] internal static class SafeNativeMethods { [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern bool IsWindowVisible(HandleRef hWnd); [DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)] public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData); internal delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam); [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId); [DllImport(ExternDll.User32, CharSet = CharSet.Auto)] public static extern int GetWindowTextLength(HandleRef hWnd); } }