BililiveRecorder/BililiveRecorder.WPF/SingleInstance.cs
2020-11-27 18:51:02 +08:00

75 lines
2.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace BililiveRecorder.WPF
{
public static class SingleInstance
{
private static Mutex singleInstanceMutex;
private static IpcServerChannel channel;
public static event EventHandler NotificationReceived;
public static bool CheckMutex(string path)
{
const string RemoteServiceName = "SingleInstanceApplicationService";
var b64path = Convert.ToBase64String(Encoding.UTF8.GetBytes(path)).Replace('+', '_').Replace('/', '-');
var identifier = "BililiveRecorder:SingeInstance:" + b64path;
singleInstanceMutex = new Mutex(true, identifier, out var createdNew);
if (createdNew)
{
channel = new IpcServerChannel(new Dictionary<string, string>
{
["name"] = identifier,
["portName"] = identifier,
["exclusiveAddressUse"] = "false"
}, new BinaryServerFormatterSinkProvider
{
TypeFilterLevel = TypeFilterLevel.Full
});
ChannelServices.RegisterChannel(channel, true);
RemotingServices.Marshal(new IPCRemoteService(), RemoteServiceName);
}
else
{
ChannelServices.RegisterChannel(new IpcClientChannel(), true);
var remote = (IPCRemoteService)RemotingServices.Connect(typeof(IPCRemoteService), $"ipc://{identifier}/{RemoteServiceName}");
remote?.Notify();
}
return createdNew;
}
public static void Cleanup()
{
singleInstanceMutex?.Close();
singleInstanceMutex = null;
if (channel != null)
{
ChannelServices.UnregisterChannel(channel);
channel = null;
}
}
private static void ActivateFirstInstanceCallback() => NotificationReceived?.Invoke(null, EventArgs.Empty);
private class IPCRemoteService : MarshalByRefObject
{
public void Notify() => Application.Current?.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)ActivateFirstInstanceCallback);
public override object InitializeLifetimeService() => null;
}
}
}