Introduction
I have noticed that although there are other articles about Single Instance applications, there seems to be one particular niche that has not been served. What I've done here is tried to assemble wisdom from others, with gratitude for their contributions, in a way that I hope is helpful.
Background
Creating a "Single Instance" application must be a very common need because there are tons of articles about it, and not just here on The Code Project. Google for "C# single instance" and you'll find pages of links on the topic.
I wanted to implement a solution that was as SIMPLE and ELEGANT as possible, with as little code as possible. I wanted the following functionality:
- When the user tries to open the application a second time, a second instance does not open on the screen.
- Instead the first instance comes to the foreground. If it is minimized, it is restored.
- If the application is minimized to the SYSTEM TRAY, then it is restored from there.
(Also, I wanted multiple applications to be able to use the exact same code without having strange behaviors arise.)
I found many solutions that could meet the first two requirements, but not the third. The solutions that did meet my third requirement seemed convoluted. Do I really want my application to listen on a port or write a registry key just for this tiny bit of functionality? Seems overkill.
Finally I was able to piece together a solution, drawing ideas from a variety of sources, that is simple enough for my tastes but still meets all my requirements.
Goal #1: Prevent a Second Instance from Opening
It seems that there are three basic approaches to accomplishing this:
- Use a Mutex
- Cycle through the process list to see if a process with the same name is already running
- Use the Visual Basic system for single instance apps (which you can access from C#)
I like the MUTEX approach.
Cycling through processes seems slow, clunky, and error prone. While many articles I found advocate this approach, the real experts seem to agree that using a Mutex is better. (For a description of the problems with using Process.GetProcessesByName()
see this article: The Misunderstood Mutex.)
"Mutex" stands for Mutual Exclusion. In a nutshell, a Mutex is a program object that prevents the concurrent use of a common resource.
There are a few different ways of implementing a Mutex-based approach. Here is the way I like the best:
[STAThread]
static void Main()
{
bool onlyInstance = false;
Mutex mutex = new Mutex(true, "UniqueApplicationName", out onlyInstance);
if (!onlyInstance) {
return;
}
Application.Run(new MainForm);
GC.KeepAlive(mutex);
}
This approach is discussed in the article, Ensuring that only a single instance of a .NET application is running.
I like this approach because it doesn't require much code. It doesn't use the WaitOne()
method, because that is unnecessary.
Notice the last line of code: GC.KeepAlive()
The purpose of this is to protect the Mutex from garbage collection until the program closes. You need to somehow protect the Mutex from garbage collection, or else after your program has been running for a while the Mutex will disappear and then the user will be able to open a second instance.
There are other ways of protecting the Mutex from garbage collection. You can use a static
variable for the Mutex. Or you can do as the following article suggests, and put the Mutex in a "using
" statement:
Side note #1: The problem with "UniqueApplicationName"
Using a Mutex does present one potential security risk. A malicious hacker could conceivably prevent your application from ever opening (a "denial of service" attack of sorts) by figuring out the name of your Mutex and creating an application that takes the Mutex first. This doesn't seem like a huge concern to me, but it is possible. Moreover, it's possible that two applications could accidentally have the same name, or that a developer could re-use Mutex code without changing the Mutex name. Using a GUID for the Mutex name will help prevent this sort of thing from happening. My attached sample code shows how to do so.
Side note #2: Mutex scope
To prevent multiple instances across sessions on the same machine, preface the Mutex name with Global\ (e.g. mutexName = @"Global\" + myGuid; )
Goal #2: Activate the First Instance
You can use WinAPI functions to activate the window and bring it to the foreground.
First you need to get the handle of the window. I've seen a few different approaches to this (like cycling through the process list or enumerating windows). In a previous version of this article I used the FindWindow()
API function, but I've since learned there are drawbacks to using that function.
For a discussion of why FindWindow()
is evil, see the following article:
The example code below still uses FindWindow()
, but later in the article I'll show a better way.
[DllImportAttribute ("user32.dll")]
public static extern IntPtr FindWindow (string lpClassName, string lpWindowName);
[DllImportAttribute ("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImportAttribute ("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public static void ShowToFront(string windowName)
{
IntPtr firstInstance = FindWindow(null, windowName);
ShowWindow(firstInstance, 1);
SetForegroundWindow(firstInstance);
}
Then just insert a call to ShowToFront()
in the following code:
if (!onlyInstance) {
ShowToFront(applicationName);
return;
}
Goal #3. If the First Instance is Minimized to the System Tray (aka "Notification Area"), Restore It
This is where it gets tricky. Rather than using WinAPI functions in the second instance to grab the first instance and force it out of hiding, what I really wanted was a way for the second instance to signal the first instance that it should show itself.
How can one instance of my application communicate with another? The solutions I found seemed too complex. One used Memory Mapped Files (a way to share memory between applications). Another used Remoting (a way for applications to communicate via a socket, your standard network client/server stuff).
Then I found the article, C# .NET Single Instance Application.
I don't like the author's way of doing the Mutex, but his idea of using PostMessage
is brilliant. It requires far less code and seems far more elegant than Remoting.
Some care must be made when using HWND_BROADCAST
. If you broadcast a message code that other applications use internally for their own purposes, then wacky behavior could ensue. One way to avoid this is to use RegisterWindowMessage()
. This will generate a message code that is guaranteed to be unique.
We want to create code that can be re-used in multiple applications. Therefore, the call to RegisterWindowMessage()
must include application specific text. One way to accomplish this is to append the assembly GUID to the name of the message.
Putting It All Together
I put all my WinAPI stuff in a separate class called WinApi
.
static public class WinApi
{
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
public static int RegisterWindowMessage(string format, params object[] args)
{
string message = String.Format(format, args);
return RegisterWindowMessage(message);
}
public const int HWND_BROADCAST = 0xffff;
public const int SW_SHOWNORMAL = 1;
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImportAttribute ("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImportAttribute ("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public static void ShowToFront(IntPtr window)
{
ShowWindow(window, SW_SHOWNORMAL);
SetForegroundWindow(window);
}
}
And I put all the Mutex code in a separate class called SingleInstance
.
static public class SingleInstance
{
public static readonly int WM_SHOWFIRSTINSTANCE =
WinApi.RegisterWindowMessage("WM_SHOWFIRSTINSTANCE|{0}", ProgramInfo.AssemblyGuid);
static Mutex mutex;
static public bool Start()
{
bool onlyInstance = false;
string mutexName = String.Format("Local\\{0}", ProgramInfo.AssemblyGuid);
mutex = new Mutex(true, mutexName, out onlyInstance);
return onlyInstance;
}
static public void ShowFirstInstance()
{
WinApi.PostMessage(
(IntPtr)WinApi.HWND_BROADCAST,
WM_SHOWFIRSTINSTANCE,
IntPtr.Zero,
IntPtr.Zero);
}
static public void Stop()
{
mutex.ReleaseMutex();
}
}
The Mutex name and the call to RegisterWindowMessage()
both require an application-specific GUID. I use a separate class called ProgramInfo
for this. ProgramInfo.AssemblyGuid
gets the GUID that is automatically associated with the assembly.
static public class ProgramInfo
{
static public string AssemblyGuid
{
get
{
object[] attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), false);
if (attributes.Length == 0) {
return String.Empty;
}
return ((System.Runtime.InteropServices.GuidAttribute)attributes[0]).Value;
}
}
}
To make all this code work in your application, you just need to do two things.
Firstly, in your Main() function, you must call the functions from SingleInstance
... Start()
, ShowFirstInstance()
, and Stop()
.
static class Program
{
[STAThread]
static void Main()
{
if (!SingleInstance.Start()) {
SingleInstance.ShowFirstInstance();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try {
MainForm mainForm = new MainForm();
Application.Run(mainForm);
} catch (Exception e) {
MessageBox.Show(e.Message);
}
SingleInstance.Stop();
}
}
And secondly within your main form, the following code must be added:
protected override void WndProc(ref Message message)
{
if (message.Msg == SingleInstance.WM_SHOWFIRSTINSTANCE) {
ShowWindow();
}
base.WndProc(ref message);
}
public void ShowWindow()
{
WinApi.ShowToFront(this.Handle);
}
See what's happening here? Instead of having Instance #2 use FindWindow()
to find and show the window for Instance #1, it broadcasts a message that says "show yourself." Instance #1 hears that message, and then shows itself.
If your application is minimized to the system tray, ShowWindow
is where you put the code to restore it. This sample code shows one way to accomplish that.
Going Further
Some people need to go a step further and pass command line arguments from the second instance to the first instance. If you need to accomplish that, then it seems you have two options:
- You can use the Visual Basic system for single instance apps (which is accessible from C#) as described in this article.
- Or you can use a strictly C# solution that uses something like Remoting to communication between the instances. The best article I've found on that is this article.
History
- 29th January, 2009: Initial post
- 9th August, 2009: Major revision, got rid of
FindWindow()