Introduction
Here is one more solution to solve the one instance application issue. The
main distinguishing feature of this implementation is simplicity. It's not
bound to MFC and can be used in pure Win32 application, no matter GUI or
console. But MFC version is also present. There are two demo projects (MFC and Win32) to demonstrate how it works. Try
to start several instances to see what happens.
How does this work
The first instance of application creates file mapping, registers window
message and save its thread ID in the file mapping. The second
instance opens the file mapping, copies its command line to the file mapping
and posts registered window message to the first instance thread. The
posted message notifies the first instance that command line of the
second instance is available. So, it uses one file mapping and one registered windows
message. Implementation is very lightweight - you don't have to pay much
for such a common task.
Background
I wrote this in response to
Single Instance Application by Justin Hallet
. I found his implementation too complicated (one mutex, one thread, one
file mapping, two events - whoa, this is overhead!). Indeed, because such a code keeps the computer running needlessly, it also
needlessly increases the entropy of the universe, thereby hastening said heat
death. In short, such a code is quite environmentally unfriendly and should be
considered a threat to our species :). (Copyright � 2002 Herb Sutter
)
Implementation presented here is made as simple as possible.
Using the code with MFC
It's very simple to use it with MFC.
- Derive your application class from
CSingleInstanceApp
instead of
CWinApp
. Do not forget to include SingleInstanceApp.h in your application class
header.
class CMyApp : public CSingleInstanceApp
{
};
-
Replace all references to
CWinApp
with CSingleInstanceApp
in your
CSingleInstanceApp
-derived class.
-
Add the code to the
CMyApp
constructor:
CMyApp::CMyApp() :
CSingleInstanceApp(TEXT("{49E4CD26-9489-4474-91B0-2A30F6CA3097}"))
Please note, that argument to CSingleInstanceApp
constructor must be the
pointer to the system unique string (it is used to name the file mapping
and to register the window message). Replace it with newly generated GUID.
- Add the check to
InitInstance
method of your application class.
BOOL CMyApp::InitInstance()
{
if (!AmITheFirst())
return false;
-
Optional. Override the
CSingleInstanceApp::OnSecondInstance
method to get
notified when the second instance is being tried to start. You can
use here the CSingleInstanceApp::GetSecondInstanceCmdLine()
method to get the
second instance command line.
Using the code without MFC
It's also very simple.
-
Define
UINT
variable and SingleInstanceApp
instance like this:
UINT uSecondInstanceMessage;
SingleInstanceApp single(TEXT(
"{B0C9E56F-687A-4c1f-9862-2F4D0F748827}"),
uSecondInstanceMessage);
These two must be accessible from scope of the application message loop. The
easiest way to do this is to define it at the global scope.
-
Having
single
defined at the global scope add the check at your
WinMain
function:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
if (!single.AmITheFirst())
return false;
-
Optional. Registered message posted by
PostThreadMessage()
function can't be dispatched to a window procedure. So, add the code
to your application message loop to get notified when the second
instance is being tried to start. You can use here the SingleInstanceApp::GetSecondInstanceCmdLine()
method
to get the second instance command line:
while (GetMessage(&msg, NULL, 0, 0))
{
if (uSecondInstanceMessage == msg.message)
{
continue;
}
That's all folks :)