JD2022-TU1/main/tools/framework/JD.TeaBoxAddinSystem/Bootstrap/ApplicationInstanceManager.cs

214 lines
6.4 KiB
C#

using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Threading;
using JD.Kernel.StaticHelpers;
namespace JD.TeaBoxAddinSystem.Bootstrap
{
/// <summary>
/// This class is used to check whether there already exists other instances of the application running,
/// and to communicate with the "main" instance.
/// </summary>
/// <remarks>
/// This class assumes that this library is in the same directory as the entry exe.
/// </remarks>
public sealed class ApplicationInstanceManager : MarshalByRefObject, IDisposable
{
#region Delegates
/// <summary>
/// Delegate for method that can receive a string array.
/// </summary>
/// <param name="args"></param>
public delegate object ReceiveDelegate(string[] args);
#endregion
#region Variables
private const string ServiceName = "Remoting";
private readonly string m_uniqueIdentifier;
private readonly IpcChannel m_ipcChannel;
private readonly Mutex m_mutex = null;
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily")]
public ApplicationInstanceManager(string uniqueIdentifier)
{
Throw.IfEmpty(uniqueIdentifier, "uniqueIdentifier");
m_uniqueIdentifier = uniqueIdentifier;
/*LogService.LogMessage("Trying to lock '" + UniqueIdentifier + "' mutex.", MessageImportance.Debug);
m_mutex = new Mutex(false, UniqueIdentifier);
if (m_mutex.WaitOne(1, true))
{
// We locked it, we are the first instance.
m_ipcChannel = new IpcChannel(UniqueIdentifier);
ChannelServices.RegisterChannel(m_ipcChannel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ApplicationInstanceManager), ServiceName, WellKnownObjectMode.SingleCall);
}
else
{
// Not the first instance.
m_mutex.Close();
m_mutex = null;
}*/
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["portName"] = UniqueIdentifier + "<" + Process.GetCurrentProcess().Id + ">";
m_ipcChannel = new IpcChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(m_ipcChannel, false);
}
/// <summary>
/// DO NOT USE THIS CONSTRUCTOR.
/// </summary>
public ApplicationInstanceManager()
{
}
/// <summary>
/// Finalizer.
/// </summary>
~ApplicationInstanceManager()
{
Dispose();
}
/// <summary>
/// Disposes this object.
/// </summary>
public void Dispose()
{
if (m_mutex != null)
{
m_mutex.Close();
}
if (m_ipcChannel != null)
{
ChannelServices.UnregisterChannel(m_ipcChannel);
m_ipcChannel.StopListening(null);
}
GC.SuppressFinalize(this);
}
#endregion
#region Properties
/// <summary>
/// Unique Identifier.
/// </summary>
public string UniqueIdentifier
{
get
{
return m_uniqueIdentifier;
}
}
#endregion
#region Methods
/// <summary>
/// Sends a string array to the "main" instance.
/// </summary>
/// <param name="s"></param>
public object Send(string[] s)
{
return Send(UniqueIdentifier, s);
}
/// <summary>
/// Sends a string array to the "main" instance of the application specified by <paramref name="uniqueIdentifier"/>.
/// </summary>
/// <param name="s"></param>
/// <param name="uniqueIdentifier"></param>
public static object Send(string uniqueIdentifier, string[] s)
{
string completeUrl = "ipc://" + uniqueIdentifier + "/" + ServiceName;
try
{
ApplicationInstanceManager mainInstance = Activator.GetObject(typeof(ApplicationInstanceManager), completeUrl) as ApplicationInstanceManager;
return mainInstance.OnReceived(s);
}
catch (Exception e)
{
LogService.LogService.LogError("Error while sending string array to main instance: {0}", e);
throw;
}
}
internal static object LocalSend(string[] args)
{
return OnReceivedInternal(args);
}
/// <summary>
/// Returns true if there is already an instance running with the given <paramref name="uniqueIdentifier"/>.
/// </summary>
public static bool IsInstanceRunning(string uniqueIdentifier)
{
Mutex mutex = new Mutex(false, uniqueIdentifier);
bool result = !mutex.WaitOne(1, true);
mutex.Close();
return result;
}
#endregion
#region Events
/// <summary>
/// Fired when a string array is received from other temporary instances.
/// </summary>
public static event ReceiveDelegate Received;
private static object OnReceivedInternal(string[] s)
{
if (Received != null)
{
return Received(s);
}
return null;
}
/// <summary>
/// Triggers the <see cref="Received"/> event.
/// </summary>
/// <remarks>
/// Method needs to be public to be called remotely.
/// </remarks>
/// <param name="s">String array</param>
/// <returns></returns>
public object OnReceived(string[] s)
{
return OnReceivedInternal(s);
}
#endregion
}
}