In the class of my application main I created a static named Mutex:
static class Program {
static Mutex mutex = new Mutex(true, "MyMuteX");
[STAThread]
...
}
By having a named mutex allows us to stack synchronization across threads and processes which is just the magic I'm looking for.
Mutex.WaitOne has an overload that specifies an amount of time for us to wait. Since we're not actually wanting to synchronizing our code (more just check if it is currently in use) we use the overload with two parameters: Mutex.WaitOne(Timespan timeout, bool exitContext). Wait one returns true if it is able to enter, and false if it wasn't. In this case, we don't want to wait at all; If our mutex is being used, skip it, and move on, so we pass in TimeSpan.Zero (wait 0 milliseconds), and set the exitContext to true so we can exit the synchronization context before we try to aquire a lock on it. Using this, we wrap our Application.Run code inside something like this:
static class Program {
static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
[STAThread]
static void Main() {
if(mutex.WaitOne(TimeSpan.Zero, true)) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
mutex.ReleaseMutex();
} else {
MessageBox.Show("only one instance at a time");
}
}
}
So, if our app is running, WaitOne will return false, and we'll get a message box.
Instead of showing a message box, I opted to utilize a little Win32 to notify my running instance that someone forgot that it was already running (by bringing itself to the top of all the other windows). To achieve this I used PostMessage to broadcast a message to every window (that I had previously registered with RegisterWindowMessage) then my second instance exits. The running application instance would receive that notification and process it. In order to do that, I overrode WndProc in my main form and listened for my custom notification. When I received that notification I set the form's TopMost property to true to bring it up on top.
Here is what I ended up with:
Program.cs
static class Program {
static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
[STAThread]
static void Main() {
if(mutex.WaitOne(TimeSpan.Zero, true)) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
mutex.ReleaseMutex();
} else {
// send our Win32 message to make the currently running instance
// jump on top of all the other windows
NativeMethods.PostMessage(
(IntPtr)NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SHOWME,
IntPtr.Zero,
IntPtr.Zero);
}
}
}
NativeMethods.cs
// this class just wraps some Win32 stuffthat we're going to use
internal class NativeMethods {
public const int HWND_BROADCAST = 0xffff;
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
}
and
Form1.cs (front side partial)
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void WndProc(ref Message m) {
if(m.Msg == NativeMethods.WM_SHOWME) {
ShowMe();
}
base.WndProc(ref m);
}
private void ShowMe() {
if(WindowState == FormWindowState.Minimized) {
WindowState = FormWindowState.Normal;
}
// get our current "TopMost" value (ours will always be false though)
bool top = TopMost;
// make our form jump to the top of everything
TopMost = true;
// set it back to whatever it was
TopMost = top;
}
}
Subscribe to:
Post Comments (Atom)


4 comments:
Perhaps credit should be given to the actual author (me) of this post...
Original post at:
http://sanity-free.org/143/csharp_dotnet_single_instance_application.html
full credit goes to you...and thanks for visiting my blog
We had an immediate requirement to do a single instance application and at that time I got ur post, saved that thing into my post for future refernces....
I have used this method for single instance application. My application already using .net remoting to access server application. But with your method, client application is unable to access server application
Regards
Sheraz
sheraz,
I have used this method for an application which does connects to the server(I dont know if the name is correct for this appln).But in our scenario we have used webservices....Does that make any diff?
I would like to know more about the issues....
Regards
Ajith
Post a Comment