Revision: 61662
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at January 4, 2013 02:38 by skivsoft
Initial Code
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) { var wndRef = new HandleRef(lParam, hWnd); // 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; appStartMutex = new Mutex( 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) { HandleRef wndRef = new HandleRef(process, process.MainWindowHandle); UnsafeNativeMethods.ShowWindowAsync(wndRef, NativeMethods.SW_NORMAL); UnsafeNativeMethods.SetForegroundWindow(wndRef); } else { var callback = new SafeNativeMethods.EnumThreadWindowsCallback(FindInvisibleWindow); SafeNativeMethods.EnumWindows(callback, new IntPtr(process.Id)); 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 static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero); 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); } }
Initial URL
Initial Description
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.
Initial Title
single-instance-check using mutex. With showing previous instance MainWindow.
Initial Tags
Initial Language
C#