comparison 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
comparison
equal deleted inserted replaced
9:904a9faadf8b 10:443821e55f06
1 namespace Chronos
2 {
3 using System;
4 using System.Collections.Generic;
5 using System.Diagnostics.CodeAnalysis;
6 using System.Runtime.Remoting;
7 using System.Runtime.Remoting.Channels;
8 using System.Runtime.Remoting.Channels.Ipc;
9 using System.Runtime.Serialization.Formatters;
10 using System.Threading;
11 using System.Windows;
12
13 /// <summary>
14 /// http://www.fishbowlclient.com/
15 /// </summary>
16 public static class SingleInstance
17 {
18 #region · Consts ·
19
20 private const string RemoteServiceName = "SingleInstanceApplicationService";
21
22 #endregion
23
24 #region · Inner Types ·
25
26 private class IpcRemoteService : MarshalByRefObject
27 {
28 #region · Methods ·
29
30 /// <summary>Activate the first instance of the application.</summary>
31 /// <param name="args">Command line arguemnts to proxy.</param>
32 public void InvokeFirstInstance(IList<string> args)
33 {
34 if (Application.Current != null && !Application.Current.Dispatcher.HasShutdownStarted)
35 {
36 Application.Current.Dispatcher.BeginInvoke((Action<object>)((arg) => SingleInstance.ActivateFirstInstance((IList<string>)arg)), args);
37 }
38 }
39
40 /// <summary>Overrides the default lease lifetime of 5 minutes so that it never expires.</summary>
41 public override object InitializeLifetimeService()
42 {
43 return null;
44 }
45
46 #endregion
47 }
48
49 #endregion
50
51 #region · Events ·
52
53 public static event EventHandler<SingleInstanceEventArgs> SingleInstanceActivated;
54
55 #endregion
56
57 #region · Fields ·
58
59 private static Mutex SingleInstanceMutex;
60 private static IpcServerChannel Channel;
61
62 #endregion
63
64 #region · Methods ·
65
66 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
67 public static void SafeDispose<T>(ref T disposable) where T : IDisposable
68 {
69 // Dispose can safely be called on an object multiple times.
70 IDisposable t = disposable;
71 disposable = default(T);
72
73 if (null != t)
74 {
75 t.Dispose();
76 }
77 }
78
79 public static bool InitializeAsFirstInstance(string applicationName)
80 {
81 IList<string> commandLineArgs = Environment.GetCommandLineArgs() ?? new string[0];
82
83 // Build a repeatable machine unique name for the channel.
84 string appId = applicationName + Environment.UserName;
85 string channelName = String.Format("{0}:SingleInstanceIPCChannel", appId);
86
87 bool isFirstInstance;
88
89 SingleInstanceMutex = new Mutex(true, appId, out isFirstInstance);
90
91 if (isFirstInstance)
92 {
93 CreateRemoteService(channelName);
94 }
95 else
96 {
97 SignalFirstInstance(channelName, commandLineArgs);
98 }
99
100 return isFirstInstance;
101 }
102
103 public static void Cleanup()
104 {
105 SafeDispose(ref SingleInstanceMutex);
106
107 if (Channel != null)
108 {
109 ChannelServices.UnregisterChannel(Channel);
110 Channel = null;
111 }
112 }
113
114 #endregion
115
116 #region · Private Methods ·
117
118 private static void CreateRemoteService(string channelName)
119 {
120 Channel = new IpcServerChannel(
121 new Dictionary<string, string>
122 {
123 { "name", channelName },
124 { "portName", channelName },
125 { "exclusiveAddressUse", "false" },
126 },
127 new BinaryServerFormatterSinkProvider { TypeFilterLevel = TypeFilterLevel.Full });
128
129 ChannelServices.RegisterChannel(Channel, true);
130 RemotingServices.Marshal(new IpcRemoteService(), RemoteServiceName);
131 }
132
133 private static void SignalFirstInstance(string channelName, IList<string> args)
134 {
135 var secondInstanceChannel = new IpcClientChannel();
136 ChannelServices.RegisterChannel(secondInstanceChannel, true);
137
138 string remotingServiceUrl = String.Format("ipc://{0}/{1}", channelName, RemoteServiceName);
139
140 // Obtain a reference to the remoting service exposed by the first instance of the application
141 var firstInstanceRemoteServiceReference = (IpcRemoteService)RemotingServices.Connect(typeof(IpcRemoteService), remotingServiceUrl);
142
143 // Pass along the current arguments to the first instance if it's up and accepting requests.
144 if (firstInstanceRemoteServiceReference != null)
145 {
146 firstInstanceRemoteServiceReference.InvokeFirstInstance(args);
147 }
148 }
149
150 private static void ActivateFirstInstance(IList<string> args)
151 {
152 if (Application.Current != null && !Application.Current.Dispatcher.HasShutdownStarted)
153 {
154 var handler = SingleInstanceActivated;
155
156 if (handler != null)
157 {
158 handler(Application.Current, new SingleInstanceEventArgs { Args = args });
159 }
160 }
161 }
162
163 #endregion
164 }
165 }