Library tutorials & articles

Avoiding Multiple Instances of an Application

Shared Variable: A different problem

Another method which has been proposed is to use a shared variable between all instances of the application. This can be done by creating a shared data segment. The technique is of the form:

#pragma comment(linker, "/SECTION:.shr,RWS")
#pragma data_seg(".shr")
HWND hGlobal = NULL;
#pragma data_seg()

// in the startup code:
// g_hWnd is set when the main window is created.

BOOL CMyApp::InitInstance()
    {
     bool AlreadyRunning;

     HANDLE hMutexOneInstance = ::CreateMutex( NULL, TRUE,
	   _T("MYAPPNAME-088FA840-B10D-11D3-BC36-006067709674"));

     AlreadyRunning = (GetLastError() == ERROR_ALREADY_EXISTS);

     if (hMutexOneInstance != NULL) 
        {
         ::ReleaseMutex(hMutexOneInstance);
        }

     if ( AlreadyRunning )
	 { /* kill this */
	  HWND hOther = g_hWnd;

         if (hOther != NULL)
	     { /* pop up */
             ::SetForegroundWindow(hOther);

             if (IsIconic(hOther))
                { /* restore */
                 ::ShowWindow(hOther, SW_RESTORE);
                } /* restore */
            } /* pop up */

         return FALSE; // terminates the creation
        } /* kill this */
     // ... continue with InitInstance
     return TRUE;
    } // CMyApp::InitInstance

This almost works. It avoids the fundamental race condition, because the CreateMutex call is an atomic operation. No matter what the relative timings of the two processes are, exactly one of them will create the Mutex first, and the other will get the ERROR_ALREADY_EXISTS. Note that I used GUIDGEN to get a guaranteed-unique ID. 

The use of the shared variable presents a problem. This shared variable is only shared with other instances from the same executable. This means that if you run a version of the debug executable, and a version of the release executable, one cannot find the other's window to pop it up. Thus, when an instance finds that it is a duplicate (they still share the same Mutex name), it cannot find its other instance to pop it up. This will confuse you. 

The code, however, is simpler than mine; it doesn't need the EnumWindows handler, or the code inside it, or a user-defined Registered Window Message, or a handler in CMainFrame.  

I don't understand why the Mutex is created in owned mode (the second parameter is TRUE). The Microsoft documentation even says that when doing a CreateMutex from separate threads that this parameter must always be FALSE because otherwise it is impossible to determine which thread actually owns the Mutex. Since this Mutex is not used in any way in the code, the use of the TRUE parameter doesn't seem to have any value.

Daniel Lohmann has observed that shared memory is shared even if the processes run under different user accounts, as long as the instances are on the same machine. Of course it's also shared if the instances reside on different desktops. Therefore, the use of shared variables has marginal value--and may even be harmful--when you generalize the notion as he indicates in his suggestions in the next section.

Comments

  1. 13 Jul 2005 at 11:38

    I am making a single instance appilcation and have followed all your suggestions . And i am really thankful to you for writing such an informative article.But i have a problem. It is my requirement that user can close my running application from the command prompt.To impliment this i am sending a message (WM_COPYDATA) from new instance which tries to launch but since it finds that an instance is already running it passes the cmdLine parameter from new instance to already existing instance and if the cmdLine parameter is /exit the application is closed. Everything works Like a charm.But problem is this. If i keep the exe in the folder named similar to the window name of my application  then the second instance is not able to find the first instance and thus the application does not exit when it should have exited. If i change the name of the folder in which the exe is residing then everything works fine.
    I just want to understand why is it happening and would love to have your views on this one.

  2. 17 May 2004 at 23:59
    The article is realy good Even other tips and artcles by Joseph M. Newcomer are excellent for those who want to master vc++
  3. 01 Dec 2003 at 11:36

    Brilliant article!! Here it is again, boiled down to cookbook code for your MyApp.cpp file.
    Many thanks to Joseph Newcomer & Daniel Lohmann. // Mark Malyj


    //Avoiding Multiple Instances of an Application


    //Step 1 of 5.
    //Include exclusion.h at the top of app.cpp.

    include "exclusion.h"



    //Step 2 of 5.
    //Define UNIQUE_GUID after the includes
    //Run Visual Studio tool GUIDGEN.EXE to generate a worldwide-unique GUID for this app;
    //choose option 4: registry format, Copy, and define here (DON'T USE this SAMPLE GUID!):

    define UNIQUE_GUID _T("{088FA840-B10D-11D3-BC36-006067709674}")



    //Step 3 of 5.
    //Use a shared variable between all instances of the application.
    //This can be done by creating a shared data segment.
    //Place this code block following all includes in the App .cpp file

    pragma comment(linker, "/SECTION:.shr,RWS")


    pragma data_seg(".shr")


    HWND g_hWnd = NULL;

    pragma data_seg()



    //Step 4 of 5.
    //Place this code block at the top of App::InitInstance
    bool AlreadyRunning;
    HANDLE hMutexOneInstance = ::CreateMutex( NULL, TRUE,
       //Choose UNIQUETODESKTOP, UNIQUETOSYSTEM,
       //UNIQUETOSESSION, or UNIQUETOTRUSTEE here:
       createExclusionName(UNIQUEGUID, UNIQUETODESKTOP));
    AlreadyRunning = (GetLastError() == ERROR
    ALREADYEXISTS);
    if (hMutexOneInstance != NULL)
    {
       ::ReleaseMutex(hMutexOneInstance);
    }
    if ( AlreadyRunning )
    { /* kill this */
       HWND hOther = g
    hWnd;
       if (hOther != NULL)
       { /* pop up /
           :: SetForegroundWindow(hOther);
           if (IsIconic(hOther))
           { /
    restore /
               :: ShowWindow(hOther, SW_RESTORE);
           } /
    restore /
    } /
    pop up /
       return FALSE; // terminates the creation
    } /
    kill this */
    // ... continue with InitInstance


    //Step 5 of 5.
    //After Creating the Main Frame, get the handle and store it on the shared variable below.
    //Place this code block at the bottom of App::InitInstance, after the mainframe has been created or loaded
    ghWnd = mpMainWnd->m_hWnd;


    //Remember to add exlusion.h, exclusion.cpp to your project (see the original article)!!

  4. 19 Apr 2002 at 14:54

    I found this information useful for an implementation that did not involve "Avoiding Multiple Instances of an Application," but did involve use of an EnumWindows() callback loop which was freezing up before all of the windows were enumerated.  I was able to find a window that was blocking a call to GetWindowText() (it was busy with an I/O operation).  Once I discontinued using GetWindowText(), the enumeration of all windows succeeded.  I was then able to find the handle to a specific password prompt (launched by a third-party application) and automatically set the password (as well as post an IDOK message to make the window disapear).

  5. 01 Jan 1999 at 00:00

    This thread is for discussions of Avoiding Multiple Instances of an Application.

Leave a comment

Sign in or Join us (it's free).

Joseph M. Newcomer

We'd love to hear what you think! Submit ideas or give us feedback