Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / MFC
Article

Single Instance Application

Rate me:
Please Sign up or sign in to vote.
5.00/5 (10 votes)
31 Oct 20023 min read 117K   1.3K   39   16
An example approach to solving the single instance application problem with command line argument passing.

singleton image

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

guidgen image

Creating the single instance object.

singleton.cpp:

BOOL CSingletonApp::InitInstance()
{
   // We use a GUID here, so that we are sure 
   // the string is 100% unique
   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
{
   // Call parent class to handle the basic
   // functionality, (set foreground)
   CSingleInstance::WakeUp ( aCommandLine ) ;       
 
   // Process command line, for this sample send
   // new command line to the dialog
   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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
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.

Comments and Discussions

 
QuestionWhich kind of license of this code? Pin
charlesup20-Jun-23 21:15
charlesup20-Jun-23 21:15 
PraiseNice job! Pin
JetDraft14-Oct-16 8:05
JetDraft14-Oct-16 8:05 
GeneralMy vote of 5 Pin
tolw14-Mar-12 22:54
tolw14-Mar-12 22:54 
GeneralProblem in adding Message Pin
Amol Narkhede23-Feb-05 20:08
professionalAmol Narkhede23-Feb-05 20:08 
GeneralRe: Problem in adding Message [modified] Pin
Justin Hallet2-Mar-05 12:21
Justin Hallet2-Mar-05 12:21 
Generalwindow not coming to foreground Win2K Pin
ithacanz13-May-03 16:14
ithacanz13-May-03 16:14 
GeneralRe: window not coming to foreground Win2K Pin
TheAzazel26-Feb-05 4:45
TheAzazel26-Feb-05 4:45 
QuestionCan't Use Breakpoints? Pin
omasoud13-Dec-02 7:14
omasoud13-Dec-02 7:14 
GeneralVery complicated implementation Pin
MaximE5-Nov-02 23:08
MaximE5-Nov-02 23:08 
GeneralRe: Very complicated implementation Pin
Justin Hallet8-Nov-02 3:02
Justin Hallet8-Nov-02 3:02 
GeneralCode Review ... Pin
Maximilien1-Nov-02 7:25
Maximilien1-Nov-02 7:25 
GeneralRe: A couple of things bother me... Pin
Paul Watson1-Nov-02 7:26
sitebuilderPaul Watson1-Nov-02 7:26 
GeneralRe: A couple of things bother me... Pin
Andreas Saurwein1-Nov-02 11:36
Andreas Saurwein1-Nov-02 11:36 
GeneralRe: A couple of things bother me... Pin
Justin Hallet3-Nov-02 23:43
Justin Hallet3-Nov-02 23:43 
Firstly thank you for your review, much appreciated, I personally feel nothing beats a good pier review.

Coding style is flexible, I have been using the same style for many years now, and although I have had many complaints about spacing etc, I am proud to say no one has ever said my code was unreadable, which is good enough for me. Smile | :)

You may want to check out this product, "Code Styler", I think thats the name, anyway its very cool for changing layout and formating.

"constructor parameter", I often argue with this one and I have of late tended towards two phase construction, "new" object (construct), the initialise with a "create". You may ask why, will I often have many applications based on the same framework, they have to find out or decided at runtime what application they are, now if you do everything in construction it often means you must use dynamicaly allocated members of use global scope functions.

Imagine a case where CSingletonApp is used in multiple applications, now you need to change the name/guid of each application, using two phase construction you can make the decision of the name to pass in InitInstance, and just call Create with correct argument. If you had the name in the constructor, you would have to new a CSingleInstance at this point.

I am flexible about the main function name, but if SingleInstance::Create fails, this would imply you can not create a single instance. Big Grin | :-D

"mMutex is a dynamically created member"

Because we do not know the name of it yet, we need the user to supply the base name and build the mutex name on the fly.

"Why not use the C++ "bool" type? It's a small thing I know"

May be you have not done much work with multiple threads on multiple CPU systems, you can not/should not use "bool" for synchronisation between threads, you should always use a system object, like semaphores, mutexes, events. I would suggest reading:

Advanced Windows NT: The Developer's Guide to the Win32 Application Programming Interface By Jeffrey M. Richter

"traditional (in MFC at least) to have member variables prefixed..."

I know, and I used to do it, but began to realize that it is better to have your own standard you can apply to any environment or language, mine is short and simple.

m = member
g = global
l = local
a = argument

I won't get into "Hungarian Notation"....

"MapViewOfFile can fail"

Nice call I will check this one and update the code.

"MAX_DATA length"

I will check this out, the data length is checked before the string copy so it is safe, but I will check the max command line length.

"Sleeper, and WakeUp"

Sleeper calls the WakeUp function so the user can override the functionality, it is entirely optional for you to call the base class in your derived handler, you could just take the new command line and leave you application in the back ground.

"ASSERT"

You could add these, personally I think they are a very dangerous trap, ASSERT's are debug only, anything that is debug only will lead to potential release mode issue, I prefer to code defensively for both debug and release.

Again thank you for you comments and accurate review. Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.