场景:如果程序 D 已被运行 进程 A,那么再次启动程序D 运行进程 B,B 会识别到已有相同的进程,此时 B 会将 A 窗口激活弹出来,然后 B 再退出。这样不仅可以限制只能运行一个进程,而且可以让用户体验更加好。
如果程序 D 在一台计算机的多个目录下有多个副本,那么最好可以准确的激活对应目录下的进程,防止启动新版本程序时反倒将旧版本程序激活的情况。
本文大部分内容修改自 痴者工良 的文章:疯狂吐槽 MAUI 以及 MAUI 入坑知识点 。代码仅支持 Windows 平台,无论 WinForm、WPF 或 MAUI 均兼容。
internal static class ProcessManager { private static Mutex ProcessLock; private static bool HasLock; /// <summary> /// 获取进程锁 /// </summary> public static void GetProcessLock() { // 全局锁,锁名称可以自定义。 ProcessLock = new Mutex(false, $"Global\\LuYao.Toolkit[{GetUid()}]", out HasLock); if (!HasLock) { ActiveWindow(); Environment.Exit(0); } } private static string GetUid() { var bytes = Encoding.UTF8.GetBytes(Assembly.GetExecutingAssembly().Location); using (var md5 = MD5.Create()) { bytes = md5.ComputeHash(bytes); } return BitConverter.ToString(bytes); } /// <summary> /// 激活当前进程并将其窗口放到屏幕最前面 /// </summary> public static void ActiveWindow() { using (var p = Process.GetCurrentProcess()) { string pName = p.ProcessName; Process[] temp = Process.GetProcessesByName(pName); foreach (var item in temp) { if (item.MainModule.FileName == p.MainModule.FileName) { IntPtr handle = item.MainWindowHandle; SwitchToThisWindow(handle, true); break; } } } } /// <summary> /// 释放当前进程的锁 /// </summary> /// <remarks>小心使用</remarks> public static void ReleaseLock() { if (ProcessLock != null && HasLock) { ProcessLock.Dispose(); HasLock = false; } } // 将另一个窗口激活放到前台。 // Win32 API [DllImport("user32.dll")] public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab); }
然后在程序启动时调用:
/// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { public App() { ProcessManager.GetProcessLock(); } }