Introduction
This little application demonstrates an approach to solving the single instance application problem.
A key feature about this approach is that it passes the new command line to the existing instance of the application.
There is no hunting or finding windows and there is almost zero CPU overhead between instances.
To see this example in action, just run multiple instances with different command line arguments, you should see the command line arguments being passed to the initial instance.
Background (optional)
I wrote this sample after a colleague asked me how to do it; my first reaction was that’s easy just use a "named mutex".
I spent some time looking at code project and the following articles:
CSingleInstance - Single Instance Apps By PJ Naughter
Single Instance Checker By bigZidane
Both are good articles and deserve credit for there particular solution to this problem, but neither of them solved the issue of passing command line arguments.
My objectives were to demonstrate the following:
- Use of sleeping threads to handle activation, and not use post/send message.
- Abstraction classes, using "pimple" methods, interface and implementation classes.
- Use of a memory mapped file to share data between instances.
- Low user footprint, instantiate a single object and call create; user has to do no more.
- Allow command line passing, sending command line from new instance to the old instance.
Using the code
Using a CSingleInstance
class is very simple, just add as a second parent to your CWinApp
class.
singleton.h:
class CSingletonApp : public CWinApp, public CSingleInstance
{
...
} ;
Next call CSingleInstance::Create
as the first statement inside CWinApp::InitInstance
, for the argument to create you must supply a unique string.
You could supply "MyCompany_MyApplication", but this will always have a risk of someone else having the same string so I prefer using a GUID.
You can generate a GUID by running "guidgen" from a command prompt; it is supplied as part of MSVC, use the registry format.
You can use any prefix as defined by Microsoft, "Global\" or "Local\", you must be aware of the target environment for you application here as "named objects" act differently under XP, NT etc.
For more information I would suggest reading the following:
Kernel Object Name Spaces
Creating the single instance object.
singleton.cpp:
BOOL CSingletonApp::InitInstance()
{
if ( CSingleInstance::Create (_T("E435FC13-82C1-4f80-97C5-006FF4A4Exxx"))
== FALSE )
return FALSE ;
...
}
The following is optional to allow you to process the wake up or activation message, you should do this by deriving a class from CSingleInstance
, then adding a virtual method WakeUp
like so.
singleton.h:
class CSingletonApp : public CWinApp, public CSingleInstance
{
public :
virtual void WakeUp (LPCTSTR aCommandLine) const ;
} ;
singleton.cpp:
void CSingletonApp::WakeUp (LPCTSTR aCommandLine ) const
{
CSingleInstance::WakeUp ( aCommandLine ) ;
CSingletonDlg* lSingletonDlg = (CSingletonDlg*) m_pMainWnd ;
if ( lSingletonDlg )
{
lSingletonDlg -> SetCommandLine ( aCommandLine ) ;
}
}
Points of Interest
Examining the code, it may look like a lot, its not, this is partly due to my coding style and secondly due to synchronisation code.
These types of small coding tricks always seem to grow, you write a couple of lines to do something then you start adding in the defence code, catching race conditions and allocations errors.
The code contained has been checked via BoundsChecker and Purify for correctness and memory leaks, please let me know if you find any more.
History
1.0 - Initial version
Revsion History
1 Nov 2002 - Initial Editing
Developing windows applications for over 15 years now starting on Win 3.1 with Object Oriented Pascal, progressed to C++ and OWL, in 1996 switch to MFC and never looked back, now focusing on .NET/Mono.