Members

Technology Zones

IBM Learning Center

Articles

Hosted By

MaximumASP

Info

Rated
Read 29,143 times

Contents

Downloads

Related Categories

Avoiding Multiple Instances of an Application - Shared Variable: A different problem

flounder

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

  • Possible problem

    Posted by harpreetBamrah on 13 Jul 2005

    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 th...

  • Great work

    Posted by vivek.kumbhojkar on 17 May 2004

    The article is realy good Even other tips and artcles by Joseph M. Newcomer are excellent for those who want to master vc++

  • cookbook version, single instance

    Posted by malyj on 01 Dec 2003

    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 Appli...

  • Very Useful

    Posted by Randalism on 19 Apr 2002

    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 ...