I recently had the occasion to add “Single Instance” feature to a WPF application. One of the implementations previously used for this feature had a dependency on System.Windows.Forms. As a result, I decided to write up this post. Hope it helps someone.
The requirements:
- Work with all .Net client application types (console, WinForms, WPF)
- Signal the running instance to the front when second instance is attempted
- Optionally inform the user that only one copy can be run at a time
Some of the typical ways to solve this problem are:
- Use process manager to scan for running instances
- Use a listener socket
- Use a named mutex or named semaphore
1. Using the process manager.
The idea here is to simply walk through the list of running processes, counting up the processes with the same name as yourself. If this answer is greater than one, then one or more application instances of yourself are running.
Process proc = Process.GetCurrentProcess();
int count = Process.GetProcesses().Where(p.ProcessName == proc.ProcessName).Count();
if (count > 1)
{
// second instance …
}
Problems:
- Two different processes can have the same name (unlikely, but…)
- No reasonable method of signaling the first running process to bring its window to the front
2. Use a listener socket
One way to signal another application is to open a Tcp connection to it. Create a socket, bind to a port, and listen on a background thread for connections. If this succeeds, run normally. If not, make a connection to that port, which signals the other instance that a second application launch attempt has been made. The original instance can then bring its main window to the front, if appropriate.
Problems:
- Computers with no NIC/IPAddress
- “Security” software / firewalls
3. Use a named semaphore
Create a named semaphore (with a maximum count of 1, which essentially makes this a mutex) and then inspect the createdNew output parameter. If the semaphore was created new, we are the first instance. Otherwise, we are the second instance. If we are the second instance, we can use this semaphore to signal the first instance by calling Release(). If we are the first instance, then we can wait on the semaphore (in a background thread) for additional application launch attempts. [Note: If we are not dealing with a GUI application, or have nothing to do when a second launch attempt is made, we can simply skip the wait.]
bool createdNew;
using (Semaphore s = new Semaphore(0,1, "NAME", out createdNew))
{
if (!createdNew)
{
// This is a second instance
s.Release();
}
else
{
ThreadPool.QueueUserWorkItem((WaitCallback) (state=>waitOnSemaphore(s)));
// run application…
Our waitOnSemaphore() method looks something like this:
static void waitOnSemaphore(object state)
{
Semaphore s = state as Semaphore;
if (s != null)
{
while (s.WaitOne())
{
// Bring my main window to the front, if appropriate
}
}
}
The named semaphore route seems to meet all the requirements, including signaling the first instance, and working with console applications as well as both WPF and WinForms. I cannot think of any drawbacks/problems, except maybe the fact that the semaphore name must be unique and you have to deal with Global/local OS namespace issues to support multi-session scenarios. The code presented here could be improved a bit and wrapped up in a nice little class or extension method(s) to be store in a general purpose utility library. Sounds like a plan. :-)