SingleInstanceManager.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Security.Permissions;
  6. using System.Threading;
  7. using System.Windows;
  8. namespace SWRIS.Extensions
  9. {
  10. /// <summary>
  11. /// 单实例应用程序管理器
  12. /// </summary>
  13. public class SingleInstanceManager
  14. {
  15. private readonly string _mutexName;
  16. private readonly string _applicationName;
  17. private Mutex _mutex;
  18. [DllImport("user32.dll")]
  19. private static extern bool SetForegroundWindow(IntPtr hWnd);
  20. [DllImport("user32.dll")]
  21. private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  22. [DllImport("user32.dll")]
  23. private static extern bool IsIconic(IntPtr hWnd);
  24. [DllImport("user32.dll")]
  25. private static extern bool IsWindowVisible(IntPtr hWnd);
  26. // Window show commands
  27. private const int SW_HIDE = 0;
  28. private const int SW_SHOWNORMAL = 1;
  29. private const int SW_SHOWMINIMIZED = 2;
  30. private const int SW_SHOWMAXIMIZED = 3;
  31. private const int SW_SHOWNOACTIVATE = 4;
  32. private const int SW_RESTORE = 9;
  33. /// <summary>
  34. /// 当需要激活已有实例时触发
  35. /// </summary>
  36. public event Action<Process> InstanceActivated;
  37. /// <summary>
  38. /// 初始化单实例管理器
  39. /// </summary>
  40. /// <param name="applicationName">应用程序唯一名称</param>
  41. public SingleInstanceManager(string applicationName)
  42. {
  43. _applicationName = applicationName ?? throw new ArgumentNullException(nameof(applicationName));
  44. _mutexName = $@"Global\{applicationName}";
  45. }
  46. /// <summary>
  47. /// 检查是否已是运行实例
  48. /// </summary>
  49. /// <returns>true表示已有实例运行,false表示这是第一个实例</returns>
  50. public bool IsAlreadyRunning()
  51. {
  52. try
  53. {
  54. _mutex = new Mutex(true, _mutexName, out bool createdNew);
  55. return !createdNew;
  56. }
  57. catch (Exception ex)
  58. {
  59. // 记录日志或处理异常
  60. Debug.WriteLine($"Mutex创建失败: {ex.Message}");
  61. return false;
  62. }
  63. }
  64. /// <summary>
  65. /// 切换到已有运行实例
  66. /// </summary>
  67. /// <returns>true表示成功切换到已有实例,false表示切换失败</returns>
  68. public bool SwitchToExistingInstance()
  69. {
  70. try
  71. {
  72. Process currentProcess = Process.GetCurrentProcess();
  73. Process existingProcess = FindExistingProcess(currentProcess);
  74. if (existingProcess != null && existingProcess.MainWindowHandle != IntPtr.Zero)
  75. {
  76. ActivateProcessWindow(existingProcess);
  77. InstanceActivated?.Invoke(existingProcess);
  78. return true;
  79. }
  80. return false;
  81. }
  82. catch (Exception ex)
  83. {
  84. Debug.WriteLine($"切换到已有实例失败: {ex.Message}");
  85. return false;
  86. }
  87. }
  88. /// <summary>
  89. /// 切换到已有运行实例
  90. /// </summary>
  91. /// <returns>true表示成功切换到已有实例,false表示切换失败</returns>
  92. public bool SwitchToExistingInstance(string processName)
  93. {
  94. try
  95. {
  96. Process existingProcess = Process.GetProcessesByName(processName).FirstOrDefault();
  97. if (existingProcess != null && existingProcess.MainWindowHandle != IntPtr.Zero)
  98. {
  99. ActivateProcessWindow(existingProcess);
  100. InstanceActivated?.Invoke(existingProcess);
  101. return true;
  102. }
  103. return false;
  104. }
  105. catch (Exception ex)
  106. {
  107. Debug.WriteLine($"切换到已有实例失败: {ex.Message}");
  108. return false;
  109. }
  110. }
  111. /// <summary>
  112. /// 查找已有的应用程序进程
  113. /// </summary>
  114. private Process FindExistingProcess(Process currentProcess)
  115. {
  116. Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName);
  117. foreach (Process process in processes)
  118. {
  119. if (process.Id != currentProcess.Id &&
  120. !process.HasExited &&
  121. process.MainWindowHandle != IntPtr.Zero)
  122. {
  123. return process;
  124. }
  125. }
  126. return null;
  127. }
  128. /// <summary>
  129. /// 激活进程窗口
  130. /// </summary>
  131. private void ActivateProcessWindow(Process process)
  132. {
  133. IntPtr mainWindowHandle = process.MainWindowHandle;
  134. if (IsIconic(mainWindowHandle))
  135. {
  136. ShowWindow(mainWindowHandle, SW_RESTORE);
  137. }
  138. SetForegroundWindow(mainWindowHandle);
  139. // 如果窗口不可见,尝试显示它
  140. if (!IsWindowVisible(mainWindowHandle))
  141. {
  142. ShowWindow(mainWindowHandle, SW_SHOWNORMAL);
  143. }
  144. }
  145. /// <summary>
  146. /// 激活当前应用程序的主窗口
  147. /// </summary>
  148. public void ActivateCurrentApplication()
  149. {
  150. Application.Current.Dispatcher.Invoke(() =>
  151. {
  152. Window mainWindow = Application.Current.MainWindow;
  153. if (mainWindow != null)
  154. {
  155. if (mainWindow.WindowState == WindowState.Minimized)
  156. {
  157. mainWindow.WindowState = WindowState.Normal;
  158. }
  159. mainWindow.Show();
  160. mainWindow.Activate();
  161. mainWindow.Topmost = true;
  162. mainWindow.Topmost = false;
  163. mainWindow.Focus();
  164. }
  165. });
  166. }
  167. /// <summary>
  168. /// 释放资源
  169. /// </summary>
  170. public void Dispose()
  171. {
  172. _mutex?.Dispose();
  173. _mutex = null;
  174. }
  175. }
  176. }