119 lines
3.2 KiB
C#
119 lines
3.2 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
|