125 lines
4.8 KiB
C#

using System;
using System.Security.Permissions;
using System.Threading;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using System.Diagnostics;
using System.Runtime.Remoting.Channels.Ipc;
internal static class SingleInstanceManager
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[Serializable]
private class InstanceProxy : MarshalByRefObject
{
public static bool IsFirstInstance
{
get;
internal set;
}
public static string[] CommandLineArgs
{
get;
internal set;
}
public void SetCommandLineArgs(bool isFirstInstance, string[] commandLineArgs)
{
SingleInstanceManager.InstanceProxy.IsFirstInstance = isFirstInstance;
SingleInstanceManager.InstanceProxy.CommandLineArgs = commandLineArgs;
}
}
public class InstanceCallbackEventArgs : EventArgs
{
public bool IsFirstInstance
{
get;
private set;
}
public string[] CommandLineArgs
{
get;
private set;
}
internal InstanceCallbackEventArgs(bool isFirstInstance, string[] commandLineArgs)
{
this.IsFirstInstance = isFirstInstance;
this.CommandLineArgs = commandLineArgs;
}
}
public static bool CreateSingleInstance(string name, EventHandler<SingleInstanceManager.InstanceCallbackEventArgs> callback)
{
bool result;
switch (Environment.OSVersion.Platform)
{
case PlatformID.Unix:
case PlatformID.Xbox:
case PlatformID.MacOSX:
Console.WriteLine("IpcServerChannel constructor fails on linux and I don't know why");
Console.WriteLine("Single Instance Mode Not Supported!!!");
result = true;
return result;
}
name = name.Replace("\\", "_");
name = name.Replace("/", "_");
EventWaitHandle eventWaitHandle = null;
string name2 = string.Format("{0}-{1}", Environment.MachineName, name);
SingleInstanceManager.InstanceProxy.IsFirstInstance = false;
SingleInstanceManager.InstanceProxy.CommandLineArgs = Environment.GetCommandLineArgs();
try
{
eventWaitHandle = EventWaitHandle.OpenExisting(name2);
}
catch
{
SingleInstanceManager.InstanceProxy.IsFirstInstance = true;
}
if (SingleInstanceManager.InstanceProxy.IsFirstInstance)
{
eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, name2);
ThreadPool.RegisterWaitForSingleObject(eventWaitHandle, new WaitOrTimerCallback(SingleInstanceManager.WaitOrTimerCallback), callback, -1, false);
eventWaitHandle.Close();
SingleInstanceManager.RegisterRemoteType(name);
}
else
{
SingleInstanceManager.UpdateRemoteObject(name);
if (eventWaitHandle != null)
{
eventWaitHandle.Set();
}
Environment.Exit(0);
}
result = SingleInstanceManager.InstanceProxy.IsFirstInstance;
return result;
}
private static void UpdateRemoteObject(string uri)
{
IpcClientChannel chnl = new IpcClientChannel();
ChannelServices.RegisterChannel(chnl, true);
SingleInstanceManager.InstanceProxy instanceProxy = Activator.GetObject(typeof(SingleInstanceManager.InstanceProxy), string.Format("ipc://{0}{1}/{1}", Environment.MachineName, uri)) as SingleInstanceManager.InstanceProxy;
if (instanceProxy != null)
{
instanceProxy.SetCommandLineArgs(SingleInstanceManager.InstanceProxy.IsFirstInstance, SingleInstanceManager.InstanceProxy.CommandLineArgs);
}
ChannelServices.UnregisterChannel(chnl);
}
private static void RegisterRemoteType(string uri)
{
IpcServerChannel serverChannel = new IpcServerChannel(Environment.MachineName + uri);
ChannelServices.RegisterChannel(serverChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(SingleInstanceManager.InstanceProxy), uri, WellKnownObjectMode.Singleton);
Process currentProcess = Process.GetCurrentProcess();
currentProcess.Exited += delegate
{
ChannelServices.UnregisterChannel(serverChannel);
};
}
private static void WaitOrTimerCallback(object state, bool timedOut)
{
EventHandler<SingleInstanceManager.InstanceCallbackEventArgs> eventHandler = state as EventHandler<SingleInstanceManager.InstanceCallbackEventArgs>;
if (eventHandler != null)
{
eventHandler(state, new SingleInstanceManager.InstanceCallbackEventArgs(SingleInstanceManager.InstanceProxy.IsFirstInstance, SingleInstanceManager.InstanceProxy.CommandLineArgs));
}
}
}