Mercurial > silverbladetech
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 } |