SingleTon
1
//
InitialInstanceActivator.cs
2 // Inspired by Mike Woodring
3 // Copyright (c) 2003, Chris Sells
4 // Notes:
5 // -Uses Application.UserAppDataPath to pick a unique string composed
6 // of the app name, the app version and the user name. This
7 // gets us a unique mutex name, channel name and port number for each
8 // user running each app of a specific version.
9 // Usage:
10 /**/ /*
11TODO: Reference the System.Runtime.Remoting assembly
12using SellsBrothers;
13
14static void Main(string[] args) {
15 // Check for initial instance, registering callback to consume args from other instances
16 // Main form will be activated automatically
17 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
18 if( InitialInstanceActivator.Activate(mainForm, callback, args) ) return;
19
20 // Check for initial instance w/o registering a callback
21 // Main form will still be activated automatically
22 if( InitialInstanceActivator.Activate(mainForm) ) return;
23
24 // Check for initial instance, registering callback to consume args from other instances
25 // Main form from ApplicationContext will be activated automatically
26 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
27 if( InitialInstanceActivator.Activate(context, callback, args) ) return;
28
29 TODO: Run application
30}
31
32// Called from other instances
33static void OnOtherInstance(string[] args) {
34 TODO: Handle args from other instance
35}
36*/
37
38 using System;
39 using System.Windows.Forms;
40 using System.Threading;
41 using System.Runtime.Remoting;
42 using System.Runtime.Remoting.Lifetime;
43 using System.Runtime.Remoting.Channels;
44 using System.Runtime.Remoting.Channels.Tcp;
45
46 namespace SellsBrothers {
47 // Signature of method to call when another instance is detected
48 public delegate void OtherInstanceCallback(string[] args);
49
50 public class InitialInstanceActivator {
51 public static int Port {
52 get {
53 // Pick a port based on an application-specific string
54 // that also falls into an exceptable range
55 return Math.Abs(ChannelName.GetHashCode()/2)%(short.MaxValue - 1024) + 1024;
56 }
57 }
58
59 public static string ChannelName {
60 get {
61 return Application.UserAppDataPath.ToLower().Replace(@"/", "_");
62 }
63 }
64
65 public static string MutexName {
66 get {
67 return ChannelName;
68 }
69 }
70
71 public static bool Activate(Form mainForm) {
72 return Activate(new ApplicationContext(mainForm), null, null);
73 }
74
75 public static bool Activate(Form mainForm, OtherInstanceCallback callback, string[] args) {
76 return Activate(new ApplicationContext(mainForm), callback, args);
77 }
78
79 public static bool Activate(ApplicationContext context, OtherInstanceCallback callback, string[] args) {
80 // Check for existing instance
81 bool firstInstance = false;
82 Mutex mutex = new Mutex(true, MutexName, out firstInstance);
83
84 if( !firstInstance ) {
85 // Open remoting channel exposed from initial instance
86 string url = string.Format("tcp://localhost:{0}/{1}", Port, ChannelName);
87 MainFormActivator activator = (MainFormActivator)RemotingServices.Connect(typeof(MainFormActivator), url);
88
89 // Send arguments to initial instance and exit this one
90 activator.OnOtherInstance(args);
91 return true;
92 }
93
94 // Expose remoting channel to accept arguments from other instances
95 ChannelServices.RegisterChannel(new TcpChannel(Port));
96 RemotingServices.Marshal(new MainFormActivator(context, callback), ChannelName);
97 return false;
98 }
99
100 public class MainFormActivator : MarshalByRefObject {
101 public MainFormActivator(ApplicationContext context, OtherInstanceCallback callback) {
102 this.context = context;
103 this.callback = callback;
104 }
105
106 public override object InitializeLifetimeService() {
107 // We want an infinite lifetime as far as the
108 // remoting infrastructure is concerned
109 // (Thanks for Mike Woodring for pointing this out)
110 ILease lease = (ILease)base.InitializeLifetimeService();
111 lease.InitialLeaseTime = TimeSpan.Zero;
112 return(lease);
113 }
114
115 public void OnOtherInstance(string[] args) {
116 // Transition to the UI thread
117 if( this.context.MainForm.InvokeRequired ) {
118 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
119 this.context.MainForm.Invoke(callback, new object[] { args });
120 return;
121 }
122
123 // Let the UI thread know about the other instance
124 if( this.callback != null ) this.callback(args);
125
126 // Activate the main form
127 context.MainForm.Activate();
128 }
129
130 ApplicationContext context;
131 OtherInstanceCallback callback;
132 }
133 }
134}
135
136
2 // Inspired by Mike Woodring
3 // Copyright (c) 2003, Chris Sells
4 // Notes:
5 // -Uses Application.UserAppDataPath to pick a unique string composed
6 // of the app name, the app version and the user name. This
7 // gets us a unique mutex name, channel name and port number for each
8 // user running each app of a specific version.
9 // Usage:
10 /**/ /*
11TODO: Reference the System.Runtime.Remoting assembly
12using SellsBrothers;
13
14static void Main(string[] args) {
15 // Check for initial instance, registering callback to consume args from other instances
16 // Main form will be activated automatically
17 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
18 if( InitialInstanceActivator.Activate(mainForm, callback, args) ) return;
19
20 // Check for initial instance w/o registering a callback
21 // Main form will still be activated automatically
22 if( InitialInstanceActivator.Activate(mainForm) ) return;
23
24 // Check for initial instance, registering callback to consume args from other instances
25 // Main form from ApplicationContext will be activated automatically
26 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
27 if( InitialInstanceActivator.Activate(context, callback, args) ) return;
28
29 TODO: Run application
30}
31
32// Called from other instances
33static void OnOtherInstance(string[] args) {
34 TODO: Handle args from other instance
35}
36*/
37
38 using System;
39 using System.Windows.Forms;
40 using System.Threading;
41 using System.Runtime.Remoting;
42 using System.Runtime.Remoting.Lifetime;
43 using System.Runtime.Remoting.Channels;
44 using System.Runtime.Remoting.Channels.Tcp;
45
46 namespace SellsBrothers {
47 // Signature of method to call when another instance is detected
48 public delegate void OtherInstanceCallback(string[] args);
49
50 public class InitialInstanceActivator {
51 public static int Port {
52 get {
53 // Pick a port based on an application-specific string
54 // that also falls into an exceptable range
55 return Math.Abs(ChannelName.GetHashCode()/2)%(short.MaxValue - 1024) + 1024;
56 }
57 }
58
59 public static string ChannelName {
60 get {
61 return Application.UserAppDataPath.ToLower().Replace(@"/", "_");
62 }
63 }
64
65 public static string MutexName {
66 get {
67 return ChannelName;
68 }
69 }
70
71 public static bool Activate(Form mainForm) {
72 return Activate(new ApplicationContext(mainForm), null, null);
73 }
74
75 public static bool Activate(Form mainForm, OtherInstanceCallback callback, string[] args) {
76 return Activate(new ApplicationContext(mainForm), callback, args);
77 }
78
79 public static bool Activate(ApplicationContext context, OtherInstanceCallback callback, string[] args) {
80 // Check for existing instance
81 bool firstInstance = false;
82 Mutex mutex = new Mutex(true, MutexName, out firstInstance);
83
84 if( !firstInstance ) {
85 // Open remoting channel exposed from initial instance
86 string url = string.Format("tcp://localhost:{0}/{1}", Port, ChannelName);
87 MainFormActivator activator = (MainFormActivator)RemotingServices.Connect(typeof(MainFormActivator), url);
88
89 // Send arguments to initial instance and exit this one
90 activator.OnOtherInstance(args);
91 return true;
92 }
93
94 // Expose remoting channel to accept arguments from other instances
95 ChannelServices.RegisterChannel(new TcpChannel(Port));
96 RemotingServices.Marshal(new MainFormActivator(context, callback), ChannelName);
97 return false;
98 }
99
100 public class MainFormActivator : MarshalByRefObject {
101 public MainFormActivator(ApplicationContext context, OtherInstanceCallback callback) {
102 this.context = context;
103 this.callback = callback;
104 }
105
106 public override object InitializeLifetimeService() {
107 // We want an infinite lifetime as far as the
108 // remoting infrastructure is concerned
109 // (Thanks for Mike Woodring for pointing this out)
110 ILease lease = (ILease)base.InitializeLifetimeService();
111 lease.InitialLeaseTime = TimeSpan.Zero;
112 return(lease);
113 }
114
115 public void OnOtherInstance(string[] args) {
116 // Transition to the UI thread
117 if( this.context.MainForm.InvokeRequired ) {
118 OtherInstanceCallback callback = new OtherInstanceCallback(OnOtherInstance);
119 this.context.MainForm.Invoke(callback, new object[] { args });
120 return;
121 }
122
123 // Let the UI thread know about the other instance
124 if( this.callback != null ) this.callback(args);
125
126 // Activate the main form
127 context.MainForm.Activate();
128 }
129
130 ApplicationContext context;
131 OtherInstanceCallback callback;
132 }
133 }
134}
135
136