Posted By

skivsoft on 01/04/13


Tagged


Versions (?)

Who likes this?

2 people have marked this snippet as a favorite

thastyle
danfinrud55


single-instance-check using mutex. With showing previous instance MainWindow.


 / Published in: C#
 

This snippet is based on jimfred's snippet. 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.

  1. namespace Utils
  2. {
  3. /// <summary>
  4. /// This checks for another instance of an app.
  5. /// Use inside Main() by calling SingleInstanceCheck.Check();
  6. /// Include this class as a sibling to Main's class.
  7. /// If another instance of the app is detected,
  8. /// - MainWindow of the first instance appears.
  9. /// - 'this' instance calls Exit.
  10. /// </summary>
  11. /// <example>
  12. /// static void Main()
  13. /// {
  14. /// SingleInstanceCheck.Check();
  15. /// Application.EnableVisualStyles();
  16. /// Application.SetCompatibleTextRenderingDefault(false);
  17. /// Application.Run(new Form1());
  18. /// }
  19. /// </example>
  20. public static class SingleInstanceCheck
  21. {
  22.  
  23. static bool FindInvisibleWindow(IntPtr hWnd, IntPtr lParam)
  24. {
  25. var wndRef = new HandleRef(lParam, hWnd);
  26. // skip visible windows
  27. if (SafeNativeMethods.IsWindowVisible(wndRef))
  28. return true;
  29. // skip windows without caption
  30. if (SafeNativeMethods.GetWindowTextLength(wndRef) == 0)
  31. return true;
  32. // retrieve process id for a window
  33. int ProcID;
  34. SafeNativeMethods.GetWindowThreadProcessId(wndRef, out ProcID);
  35. // we found or not
  36. if (ProcID == lParam.ToInt32())
  37. {
  38. UnsafeNativeMethods.ShowWindowAsync(wndRef, NativeMethods.SW_NORMAL);
  39. UnsafeNativeMethods.SetForegroundWindow(wndRef);
  40. return false;
  41. }
  42. return true;
  43. }
  44.  
  45. static public void Check()
  46. {
  47. bool isOwnedHere = false;
  48. appStartMutex = new Mutex(
  49. true,
  50. Application.ProductName,
  51. out isOwnedHere
  52. );
  53. if (isOwnedHere) return;
  54.  
  55. Process me = Process.GetCurrentProcess();
  56. foreach (Process process in Process.GetProcessesByName(me.ProcessName)) // Debug note: Set Enable the Visual Studio Hosting Process = false.
  57. {
  58. if (process.Id != me.Id) // If the ProcessName matches but the Id doesn't, it's another instance of mine.
  59. {
  60. if (process.MainWindowHandle != IntPtr.Zero)
  61. {
  62. HandleRef wndRef = new HandleRef(process, process.MainWindowHandle);
  63. UnsafeNativeMethods.ShowWindowAsync(wndRef, NativeMethods.SW_NORMAL);
  64. UnsafeNativeMethods.SetForegroundWindow(wndRef);
  65. }
  66. else
  67. {
  68. var callback = new SafeNativeMethods.EnumThreadWindowsCallback(FindInvisibleWindow);
  69. SafeNativeMethods.EnumWindows(callback, new IntPtr(process.Id));
  70. GC.KeepAlive(callback);
  71. }
  72. break;
  73. }
  74. }
  75. Environment.Exit(0); // This will kill my instance.
  76. }
  77.  
  78. // volatile is intended to prevent GC. Otherwise, GC.KeepAlive(appStartMutex) might be needed.
  79. // This appears to be a concern in In release builds but not debug builds.
  80. static volatile Mutex appStartMutex;
  81.  
  82. }
  83.  
  84. internal static class NativeMethods
  85. {
  86. public static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
  87.  
  88. public const int
  89. SW_HIDE = 0,
  90. SW_NORMAL = 1,
  91. SW_SHOWMINIMIZED = 2,
  92. SW_SHOWMAXIMIZED = 3,
  93. SW_MAXIMIZE = 3,
  94. SW_SHOWNOACTIVATE = 4,
  95. SW_SHOW = 5,
  96. SW_MINIMIZE = 6,
  97. SW_SHOWMINNOACTIVE = 7,
  98. SW_SHOWNA = 8,
  99. SW_RESTORE = 9,
  100. SW_MAX = 10,
  101. SWP_NOSIZE = 0x0001,
  102. SWP_NOMOVE = 0x0002,
  103. SWP_NOZORDER = 0x0004,
  104. SWP_NOACTIVATE = 0x0010,
  105. SWP_SHOWWINDOW = 0x0040,
  106. SWP_HIDEWINDOW = 0x0080,
  107. SWP_DRAWFRAME = 0x0020,
  108. SWP_NOOWNERZORDER = 0x0200;
  109.  
  110. }
  111.  
  112. internal class ExternDll
  113. {
  114. private ExternDll()
  115. { }
  116.  
  117. internal const string User32 = "user32.dll";
  118. }
  119.  
  120. [SuppressUnmanagedCodeSecurity]
  121. internal static class UnsafeNativeMethods
  122. {
  123. [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
  124. public static extern bool SetForegroundWindow(HandleRef hWnd);
  125.  
  126. /// <SecurityNote>
  127. /// Critical: This elevates to unmanaged code permission
  128. /// </SecurityNote>
  129. [SecurityCritical, SuppressUnmanagedCodeSecurity]
  130. [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
  131. public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
  132. }
  133.  
  134. [SuppressUnmanagedCodeSecurity]
  135. internal static class SafeNativeMethods
  136. {
  137. [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
  138. public static extern bool IsWindowVisible(HandleRef hWnd);
  139.  
  140. [DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)]
  141. public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
  142. internal delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam);
  143.  
  144. [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
  145. public static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId);
  146.  
  147. [DllImport(ExternDll.User32, CharSet = CharSet.Auto)]
  148. public static extern int GetWindowTextLength(HandleRef hWnd);
  149.  
  150. }
  151. }

Report this snippet  

You need to login to post a comment.