15 April, 2011

WPF: How to make your application a single instance (machine-wide)

If you want to make sure only a single instance is running of your application on the machine at any time; you need to use system-wide Mutexes. But, where and how do you insert this code in a WPF-application? The Main-method is kind of hidden from you…

In WPF there is no native solution to this problem => you need to solve this yourself. The good news is though, that it is not all that hard to address this problem.

How to
This is a solution that allows you to control in fine detail what is happening in your application. You need first to overwrite the default Main-method to perform the check and make sure the default app is not started. See this post for how to do this: WPF- Where is the Main method- Or how to overwrite the Main method-

Next, you need to attempt to acquire a Mutex during startup. Mutexes come in 2 flavors, a local or a system-wide version. We are in this scenario after a System-wide Mutex, so that you will be the only one that can hold on to that Mutex on the entire machine. Mutexes become system-wide if you give them a name, hence if you attempt to acquire a named mutex, you are attempting to gain systemwide access. Below is the custom Startup class (MyApp.cs):

class MyApp
{
[STAThread]
public static void Main(string[] args)
{
if (!IsFirstInstance()) return;

var app = new App();
app.InitializeComponent();
app.Run();
}

public static bool IsFirstInstance()
{
//give the mutex a name => it will be systemwide.
var mutex = new Mutex(true, "somethingunique");
return mutex.WaitOne(TimeSpan.Zero, false);
}
}

If you succeed, you are the first instance on the machine, and you are good to go. When attempting to start two instances of this application, you will see in the TaskManager on Windows that only one process is running regardless how many times you attempt to (re)start the application.


Technorati Tags:

6 comments:

gigi b. said...

It was very useful to me. Thanks!

Anonymous said...

Better than what I had before. Thanks!

Benny Skjold Tordrup said...

Don't you miss some code to release the Mutex?

Claus Konrad said...

Yes - you are right. That should be there in a finalizer!
Thx.

Benny Skjold Tordrup said...

Yet a comment. According to Microsoft documentation (http://msdn.microsoft.com/en-us/library/f55ddskf(v=vs.90)), the Mutex name must have the "Global\" prefix to be true system wide. If omitted, it will default to "Local\" prefix which will be local to the current session.

Claus Konrad said...

I was aiming for a single instance pr. my current session. According to your link, the "Global\" switch is only relevant to a Terminal Services context. A context I was not even addressing in the above post.
But, thanks for bringing that to my attention. I was not aware of that small tweak!