diff Chronosv2/source/SingleInstance.cs @ 10:443821e55f06

Initial cleaned up add from Codeplex files
author stevenh7776 stevenhollidge@hotmail.com
date Tue, 21 Feb 2012 17:25:44 +0700
parents
children 741981715d94
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Chronosv2/source/SingleInstance.cs	Tue Feb 21 17:25:44 2012 +0700
@@ -0,0 +1,165 @@
+namespace Chronos
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Runtime.Remoting;
+    using System.Runtime.Remoting.Channels;
+    using System.Runtime.Remoting.Channels.Ipc;
+    using System.Runtime.Serialization.Formatters;
+    using System.Threading;
+    using System.Windows;
+
+    /// <summary>
+    /// http://www.fishbowlclient.com/
+    /// </summary>
+    public static class SingleInstance
+    {
+        #region · Consts ·
+
+        private const string RemoteServiceName = "SingleInstanceApplicationService";
+
+        #endregion
+
+        #region · Inner Types ·
+
+        private class IpcRemoteService : MarshalByRefObject
+        {
+            #region · Methods ·
+
+            /// <summary>Activate the first instance of the application.</summary>
+            /// <param name="args">Command line arguemnts to proxy.</param>
+            public void InvokeFirstInstance(IList<string> args)
+            {
+                if (Application.Current != null && !Application.Current.Dispatcher.HasShutdownStarted)
+                {
+                    Application.Current.Dispatcher.BeginInvoke((Action<object>)((arg) => SingleInstance.ActivateFirstInstance((IList<string>)arg)), args);
+                }
+            }
+
+            /// <summary>Overrides the default lease lifetime of 5 minutes so that it never expires.</summary>
+            public override object InitializeLifetimeService()
+            {
+                return null;
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region · Events ·
+
+        public static event EventHandler<SingleInstanceEventArgs> SingleInstanceActivated;
+
+        #endregion
+
+        #region · Fields ·
+        
+        private static Mutex            SingleInstanceMutex;
+        private static IpcServerChannel Channel;
+
+        #endregion
+
+        #region · Methods ·
+
+        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        public static void SafeDispose<T>(ref T disposable) where T : IDisposable
+        {
+            // Dispose can safely be called on an object multiple times.
+            IDisposable t = disposable;
+            disposable = default(T);
+
+            if (null != t)
+            {
+                t.Dispose();
+            }
+        }
+
+        public static bool InitializeAsFirstInstance(string applicationName)
+        {
+            IList<string> commandLineArgs = Environment.GetCommandLineArgs() ?? new string[0];
+
+            // Build a repeatable machine unique name for the channel.
+            string appId        = applicationName + Environment.UserName;
+            string channelName  = String.Format("{0}:SingleInstanceIPCChannel", appId);
+
+            bool isFirstInstance;
+            
+            SingleInstanceMutex = new Mutex(true, appId, out isFirstInstance);
+
+            if (isFirstInstance)
+            {
+                CreateRemoteService(channelName);
+            }
+            else
+            {
+                SignalFirstInstance(channelName, commandLineArgs);
+            }
+
+            return isFirstInstance;
+        }
+
+        public static void Cleanup()
+        {
+            SafeDispose(ref SingleInstanceMutex);
+
+            if (Channel != null)
+            {
+                ChannelServices.UnregisterChannel(Channel);
+                Channel = null;
+            }
+        }
+
+        #endregion
+
+        #region · Private Methods ·
+
+        private static void CreateRemoteService(string channelName)
+        {
+            Channel = new IpcServerChannel(
+                new Dictionary<string, string>
+                {
+                    { "name", channelName },
+                    { "portName", channelName },
+                    { "exclusiveAddressUse", "false" },
+                },
+                new BinaryServerFormatterSinkProvider { TypeFilterLevel = TypeFilterLevel.Full });
+
+            ChannelServices.RegisterChannel(Channel, true);
+            RemotingServices.Marshal(new IpcRemoteService(), RemoteServiceName);
+        }
+
+        private static void SignalFirstInstance(string channelName, IList<string> args)
+        {
+            var secondInstanceChannel = new IpcClientChannel();
+            ChannelServices.RegisterChannel(secondInstanceChannel, true);
+
+            string remotingServiceUrl = String.Format("ipc://{0}/{1}", channelName, RemoteServiceName);
+
+            // Obtain a reference to the remoting service exposed by the first instance of the application
+            var firstInstanceRemoteServiceReference = (IpcRemoteService)RemotingServices.Connect(typeof(IpcRemoteService), remotingServiceUrl);
+
+            // Pass along the current arguments to the first instance if it's up and accepting requests.
+            if (firstInstanceRemoteServiceReference != null)
+            {
+                firstInstanceRemoteServiceReference.InvokeFirstInstance(args);
+            }
+        }
+
+        private static void ActivateFirstInstance(IList<string> args)
+        {
+            if (Application.Current != null && !Application.Current.Dispatcher.HasShutdownStarted)
+            {
+                var handler = SingleInstanceActivated;
+
+                if (handler != null)
+                {
+                    handler(Application.Current, new SingleInstanceEventArgs { Args = args });
+                }
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file