feat: 实现单实例应用程序支持
This commit is contained in:
118
SingleInstanceManager.cs
Normal file
118
SingleInstanceManager.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TimerApp
|
||||
{
|
||||
internal sealed class SingleInstanceManager : IDisposable
|
||||
{
|
||||
private const string MutexName = "Local\\TimerApp.SingleInstance";
|
||||
private const string PipeName = "TimerApp.SingleInstancePipe";
|
||||
|
||||
private readonly Mutex _mutex;
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
|
||||
private SingleInstanceManager(Mutex mutex)
|
||||
{
|
||||
_mutex = mutex;
|
||||
}
|
||||
|
||||
public static bool TryAcquire(out SingleInstanceManager? manager)
|
||||
{
|
||||
manager = null;
|
||||
|
||||
try
|
||||
{
|
||||
var mutex = new Mutex(true, MutexName, out bool createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
mutex.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
manager = new SingleInstanceManager(mutex);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SignalExistingInstance()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new NamedPipeClientStream(".", PipeName, PipeDirection.Out);
|
||||
client.Connect(200);
|
||||
using var writer = new StreamWriter(client) { AutoFlush = true };
|
||||
writer.WriteLine("show");
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StartServer(Action onShowRequested)
|
||||
{
|
||||
Task.Run(() => ServerLoop(onShowRequested, _cts.Token));
|
||||
}
|
||||
|
||||
private static async Task ServerLoop(Action onShowRequested, CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var server = new NamedPipeServerStream(
|
||||
PipeName,
|
||||
PipeDirection.In,
|
||||
1,
|
||||
PipeTransmissionMode.Byte,
|
||||
PipeOptions.Asynchronous
|
||||
);
|
||||
|
||||
await server.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
using var reader = new StreamReader(server);
|
||||
string? line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (string.Equals(line, "show", StringComparison.OrdinalIgnoreCase))
|
||||
onShowRequested();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(150, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_mutex.ReleaseMutex();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
_mutex.Dispose();
|
||||
_cts.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user