Wednesday, November 26, 2008

Creating a single-instance application

A lot has been written on the internet on how to create a single-instance application in C#. The proposed implementations fall into three categories:

  • Check if a process with the same name is already running (using GetProcessesByName). This is plain wrong because it needs administrator privileges. Furthermore it will not work if there is another process that happens to have the same name as your process.
  • Using the Microsoft.VisualBasic namespace (as explained here). This probably works OK (I have never done this), but it feels a bit wrong. Note that this approach is promoted in the book ‘Windows Forms 2.0 Programming’.
  • Using a Mutex.

Personally I think that the last approach is best, but there are some details that you need to get correct if you want to rely on this. This is the pattern that I propose:

   1: static class Program
   2: {
   3:     static Mutex s_Mutex;
   5:     /// <summary>
   6:     /// The main entry point for the application.
   7:     /// </summary>
   8:     [STAThread]
   9:     static void Main()
  10:     {
  11:         bool instantiated;
  12:         // WARNING: you need to replace the GUID in this string!
  13:         s_Mutex = new Mutex(false, "Local\\MyAppName{A6F214AB-669D-41B2-9F30-8DD5E5AC9AE1}", out instantiated);
  14:         if (!instantiated)
  15:         {
  16:             MessageBox.Show("The application is already running");
  17:             return;
  18:         }
  20:         Application.EnableVisualStyles();
  21:         Application.SetCompatibleTextRenderingDefault(false);
  22:         Application.Run(new Form1());
  23:     }
  24: }

The pattern is applied to a Winforms application, but of course it can be applied to any type of application.

For those who don’t know what a mutex is: it is a Windows kernel-object that can be used for synchronization between threads and processes. The proposed pattern tries to create a mutex with a certain name and checks if this mutex already existed. If it did, this means that our process was already started.

Here are the details that are important:

  • The mutex must be declared static, because we have to make sure that the garbage collector will never dispose it.
  • The name of the mutex should contain a GUID, which ensures that no other application uses the same name. If you don’t know how to create a GUID, click here.
  • The mutex is local, which means that every user that is logged on can create his own instance. If you don’t want this, simply ommit the ‘Local\\’.
  • The mutex contains the name of the application. As a general guideline, I think that named kernel objects should have a descriptive name. This makes it easier when debugging problems: using tools such as SysInternal’s WinObj, you can look at the state of all the kernel objects. If your object has a proper name this will be much simpler.


tertium alter ego said...

very clear explanation! thank you!

maybe you know as well how we can avoid this behavior in run time?

i mean if we have already installed an application that was developed with such a functionality. speaking simpler i'd like to launch more than one instance. any tricks?
thank you!

Kristof said...

@tertium alter ego: if I understand you correctly, you want to bypass this protection. First of all I should warn you that this is probably not a safe thing to do, most of the time this protection will be very usefull to protect you from doing something harmfull.
But if you really want to circumvent this protection, here is how you do it: start the first instance of the application. Then use Process Explorer to find the mutex (handle) that was used for the protection and kill this mutex. Then you should be able to start the second instance of the application. Note that I haven't tested this though.

Dom said...

Is "Local\\MyAppName{A6F214AB-669D-41B2-9F30-8DD5E5AC9AE1}" just a place holder of somesort, to be changed in each specific application? You can't use that in every program, can you?

I tried Application.ExecutablePath, thinking this is unique to every application, but I get the message "Part of the path can not be found." Why is that?

Kristof said...

@Dom: this is indeed a placeholder. The first part "Local\\" is mandatory. The rest "MyAppName{...}" is just meant to be a unique identifier. You need to be sure that nobody else uses the same identifier. Usually I include the name of the application (so replace "MyAppName" with the name of your application - it is OK to do this hardcoded). The reason is that this makes it easier to debug your application if you suspect there may be problems with this mutex.
The rest (between curly braces) is a GUID which makes sure that your identifier is unique. This is for the unlikely case when some other application with the same name is using exactly this same code pattern.

ashleigh said...

This works until the day your application is run on something like Windows Server 2003 or 2008, or anything that uses terminal services. Then you find that each logged in user can run their own instance of the application. Great... if the application is OK for having a single-instance-per-logged-in-user.

Some applications, though, need to use a single-instance-per-machine. In this case you need to go to a whole lot more trouble, probably put the mutex in the Global space (prefix Local -> Global). This requires Administrator rights, or similar privilege elevation and can get very messy.