Introduction
Single instance application. There may not be a topic on which there are more good quality articles, so why another? All the methods I could find rely on the main window of the first instance being visible, which won't be the case if you have an application that hides its main window, such as a system tray application. Not only does this method work in the case of a hidden window, but compares favorably for the general case too.
Background
It turns out that detecting whether your application is already running is not very hard. There are several Win32 synchronization objects that will help (this project uses events), or you can enumerate windows and search their titles (this won't work if the window is hidden though). On the other hand, it is difficult to get the first instance of the application to display its window. Especially if the window is hidden, any method using messages or manipulating the window handle won't work.
Here are some other articles you might find helpful. I'm kind of partial to this one, which also has some code for displaying an animation as the application minimizes to the sys tray area of the task bar (which, by the way, is apparently unnecessary in XP): A Single Instance Application which Minimizes to the System Tray when Closed.
Here's another recent one that has the added advantage of having no unmanaged code (unlike my example): Single Instance Application, Passing Command Line Arguments.
Using the code
The method is simple, but the implementation a little less so. This is how it's done: the application attempts to open a named event. If the event exists, then the application knows it is the second instance. In that case, it signals the event and exits. If the named event doesn't exist, then the application creates it and starts a thread which waits for the event to be signaled. If the event becomes signaled, it uses P/Invoke to call a delegate on the GUI thread. The delegate shows the window, then calls a Win32 function to bring itself to the foreground.
The code that creates and checks the event is in a class called Event
. The app's Main
will create an Event
object and use it to check whether another instance is already running. Here's what the Main
looks like:
static void Main()
{
evnt = new Event();
if ( evnt.EventAlreadyExists() )
{
evnt.SignalEvent();
}
else
{
SingleInstanceForm f = new SingleInstanceForm();
IntPtr dummy = f.Handle;
f.eventSignalled =
new EventSignalledHandler( f.evnt_EventSignalled );
evnt.SetObject( f );
Application.Run();
}
}
Notice that I don't call Application.Run()
with the form reference, which allows this application to start without showing a window. While this method doesn't need a visible window, P/Invoke does need a valid window handle. Accessing the form's handle forces .NET to create it for us.
Here's what the Event
constructor looks like:
public Event()
{
eventHandle = OpenEvent( EVENT_MODIFY_STATE |
SYNCHRONIZE, false, EVENT_NAME );
if ( eventHandle == IntPtr.Zero )
{
eventHandle = CreateEvent( IntPtr.Zero, true,
false, EVENT_NAME );
if ( eventHandle != IntPtr.Zero )
{
Thread thread =
new Thread( new ThreadStart( WaitForSignal ) );
thread.Start();
}
}
else
{
eventAlreadyExists = true;
}
}
OpenEvent
will return a valid handle only if another instance has created it. So, it's very important that the handle gets closed, which is why I implement the IDisposable
interface. If the handle were left open, your app would run the first time, but would not be able to start again until after a reboot or logout.
Win32 Synchronization object names can be defined on a per session or a per machine basis. This project prepends "Local\" to the name, which means it is only unique for the currently logged in user.
Points of interest
I learned about implementing IDisposable
from this article: Implementing IDisposable and the Dispose Pattern Properly.
One of the keys to this project is calling a method on a GUI thread from a worker thread, and in .NET, this is handled by P/Invoke. There are many good articles on CodeProject about P/Invoke, but I also want to point out a great reference site: http://www.pinvoke.net/.
I look forward to hearing comments and better or more clear ways of doing what I've shown here. One thing I don't like is that the Event
class is tied to the form class definition. One way to fix that is to create a new class that inherits from Form
and that defines the necessary delegate.
On Windows 2000, SetForegroundWindow()
doesn't always work as expected.