Limiting an application to one instance
By George Mihaescu
Summary: this article presents a technique that I've
been using for many years for limiting a Win32 application to a single
instance, with the additional feature of activating the existing instance if
already running. This technique works on all Win32 platforms (98 / ME / NT /
2000 / XP / Vista).
The problem
You have a Win32 application that you want to limit to a
single instance. Additionally, if the application is a GUI and there is already
an instance running, you may want to activate the running instance (because,
for example, the user may not be aware that an instance is already running and
attempts to start a new one simply because he did not see the running one).
The solution
My solution is based on the uniqueness of the names of Win32
kernel objects. The code below uses a semaphore for this purpose, but you may
choose to use a different kernel object if you prefer.
To implement this solution, simply add the following at the
start of your program (the example is in an MFC app, but you can do the same in
any Win32 application):
/////////////////////////////////////////////////////////////////////////
Name of the semaphore used to control the number of instances
// running
LPCTSTR INSTANCE_DETECTION_OBJECT_NAME = _T("www.abstraction.net_OneInstanceApp_v10_InstanceControl");
BOOL COneInstanceApp::InitInstance()
{
// check whether we
have already an instance running. If so,
//pass control
to that
HANDLE h_sem = ::CreateSemaphore (NULL, 0, 1,
INSTANCE_DETECTION_OBJECT_NAME);
DWORD err = ::GetLastError ();
if (err ==
ERROR_ALREADY_EXISTS)
{
//object
exists already, must have been created by
//a
previous instance, end this new instance
return
FALSE;
}
//The rest of the
code that initializes your application
...
}
The only thing to pay attention to is the name of the kernel
object; create a name that is unlikely to clash with another object of that
type (for instance, prefix it with you domain name, then continue with the application
name – and you may want to consider including the version as well, so that in
subsequent versions of the program you can change the "one instance"
rule – for example, allow only one instance of version 1.0, but also allow
side-by-side another instance of 2.0, but not multiples of each version).
Now, if the application is GUI-based, it is a nice touch to
also activate the existing running instance; in order to do this, you need to
add a shared section of memory to you application – this shared memory will
store the handle of the main window of the running instance, so that subsequent
instances will find it there and activate it. The Visual C++ linker allows creating
a shared section of memory in a program in a very simple manner, through the
use of the #pragma data_seg
directive. This is how the code above looks like with the addition of this
feature:
/////////////////////////////////////////////////////////////////////////
Name of the semaphore used to control the number of instances
// running
LPCTSTR INSTANCE_DETECTION_OBJECT_NAME = _T("www.abstraction.net_OneInstanceApp_v10_InstanceControl");
//this piece of data is shared by all
instances, so that when
//detecting that we have another
instance running, we can use
//this to activate the window of that
first instance:
#pragma data_seg ("InstanceControl")
LONG g_first_instance_main_hwnd = 0;
#pragma data_seg ()
#pragma comment
(linker, "/SECTION:InstanceControl,RWS")
BOOL COneInstanceApp::InitInstance()
{
// check whether we
have already an instance running.
//If so, pass
control to that
HANDLE h_sem = ::CreateSemaphore (NULL, 0, 1,
INSTANCE_DETECTION_OBJECT_NAME);
DWORD err = ::GetLastError ();
if (err ==
ERROR_ALREADY_EXISTS)
{
//object
exists already, must have been created by
//a
previous instance, activate that
//(we should
have the handle of its main window in
//the
shared data area).
ASSERT (g_first_instance_main_hwnd != 0);
if
(::IsWindow ((HWND) g_first_instance_main_hwnd))
{
//first
attempt to restore (in case it's minimized)
::ShowWindow ((HWND)
g_first_instance_main_hwnd,
SW_SHOWNORMAL);
//then
bring to top
::SetForegroundWindow ((HWND)
g_first_instance_main_hwnd);
}
//end this new
instance
return
FALSE;
}
// The rest of your
code here, etc
...
// The one and only
window has been initialized, so show
//and update it
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
//at this point,
since we got here, we must be the very
//first instance
(and the only one allowed
//to run) so
initialize the shared data segment with the
//main window
handle
g_first_instance_main_hwnd =
(LONG)
(m_pMainWnd -> GetSafeHwnd ());
return TRUE;
}
As I'm writing this article, it just crossed my mind that a
possible alternative to using a shared section of memory would be using a
memory mapped file as the named object that flags that an instance is already
running, and if present, look into the mapped file (by mapping a view of it)
and read from it the handle of the main window of that running instance. This
solution covers both the control of number of instances and the sharing of the
main window handle through a single mechanism, the memory mapped file. Should
work without a problem – so that's a possible choice in case you are not using
Visual C++ for development and your linker does not allow you to set up a
shared memory section as above.