单实例互斥 + 通过命名管道激活已有窗口。
- 补充文档
- 修改全局锁的名称
- 补充单元测试?(可选)
using System.IO.Pipes;
using System.Security.Cryptography;
using System.Text;
namespace Popcorn.Toolkit.Libs;
public static class SingleInstanceManager
{
private const string Command_ActivateWindow = "ActivateWindow";
private static Mutex? _processLock;
private static bool _hasLock;
public static event EventHandler? ActivateWindowRequested;
/// <summary>
/// 获取进程锁
/// </summary>
public static void EnsureSingleInstance()
{
// 全局锁,锁名称可以自定义。
string key = $"Global\\Popcorn.Toolkit[{GetUid()}]";
_processLock = new Mutex(false, key, out _hasLock);
if (_hasLock)
{
Task.Factory.StartNew(() => ServerThread(key), TaskCreationOptions.LongRunning);
}
else
{
RequestActivateWindow(key);
Environment.Exit(0);
}
}
private static string GetUid()
{
var bytes = Encoding.UTF8.GetBytes(Environment.ProcessPath ?? AppContext.BaseDirectory);
using (var md5 = MD5.Create())
{
bytes = md5.ComputeHash(bytes);
}
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
}
/// <summary>
/// 释放当前进程的锁
/// </summary>
/// <remarks>小心使用</remarks>
public static void ReleaseLock()
{
if (_processLock != null && _hasLock)
{
_processLock.Dispose();
_hasLock = false;
}
}
private static async Task ServerThread(string name)
{
while (true)
{
using (var server = new NamedPipeServerStream(name))
{
await server.WaitForConnectionAsync();
using (var reader = new StreamReader(server))
{
var command = await reader.ReadLineAsync();
if (command == Command_ActivateWindow)
{
ActivateWindowRequested?.Invoke(null, EventArgs.Empty);
}
}
}
}
}
private static void RequestActivateWindow(string key)
{
using (var client = new NamedPipeClientStream(key))
{
client.Connect(1000);
using (var writer = new StreamWriter(client))
{
writer.WriteLine(Command_ActivateWindow);
writer.Flush();
}
}
}
}
单实例互斥 + 通过命名管道激活已有窗口。