场景:如果程序 D 已被运行 进程 A,那么再次启动程序D 运行进程 B,B 会识别到已有相同的进程,此时 B 会将 A 窗口激活弹出来,然后 B 再退出。这样不仅可以限制只能运行一个进程,而且可以让用户体验更加好。
如果程序 D 在一台计算机的多个目录下有多个副本,那么最好可以准确的激活对应目录下的进程,防止启动新版本程序时反倒将旧版本程序激活的情况。
实现代码:
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();
}
}
以上代码仅支持 Windows 平台,兼容 WinForm、WPF 及 MAUI。