Take a look at this code. The first piece of code would be called very early in your program, typically inside InitInstance for an MFC program. The unique name here is created with a little help from GUIDGEN.EXE, which is part of the platform SDK.
if (WeAreAlone ("Unique_8487B3D3-4623-4551-8ACA-EDE405FDA836")) { // Proceed } else DebugMessage ("Error: app already running!"); BOOL CMyApp::WeAreAlone (LPSTR szName) { HANDLE hMutex = CreateMutex (NULL, TRUE, szName); if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(hMutex); return FALSE; } return TRUE }
Why go to this complexity ? You may well ask. Some people just check for a fixed window class, indeed Microsofts own sample code does exactly this. The problem is that if your application is started up programmatically, the second instance may be running before the first instance has managed to create its window, and the window class-based method will not work under those circumstances.
The code above will work fine if you're only worried about instances of your program running under a single user account. But what if there may be instances running under another account, such as one running under SYSTEM (a.k.a. LocalSystem) ? The code above will fail in a subtle way, because one process doesn't have access rights to the others mutex. You can assume an ERROR_ACCESS_DENIED means this situation pertains or, more properly, you can construct the mutex with an appropriate security descriptor in the first place. The code below demonstrates this:
static SECURITY_ATTRIBUTES g_sa = {0}; HANDLE g_hsa = 0; //--------------------------------------------------------------------------- BOOL IsExistingInstanceOf (LPCSTR szName) { if (OpenMutex (MUTEX_ALL_ACCESS, FALSE, szName) == NULL) { CreateNullDaclSd (); CreateMutex (&g_sa, FALSE, szName); FreeNullDaclSd (); return FALSE; } else return TRUE; } //--------------------------------------------------------------------------- // This creates a NULL-DACL-SD (a real SD, but with an all-access DACL). // Passing NULL for a security descriptor under NT5 gets you an SD // which has only CREATOR/OWNER and SYSTEM access. // // The method below gets everyone access to the object, which is what I // want for cross-account objects like exclusion mutexes (which can be // created by current user or the LOCALSYSTEM account but must be visible // to both). BOOL CreateNullDaclSd () { BOOL bRetVal = FALSE; g_sa.nLength = sizeof(g_sa); g_hsa = GlobalAlloc (GHND,SECURITY_DESCRIPTOR_MIN_LENGTH); g_sa.lpSecurityDescriptor = GlobalLock(g_hsa); g_sa.bInheritHandle = TRUE; if (InitializeSecurityDescriptor (g_sa.lpSecurityDescriptor, 1)) { if (SetSecurityDescriptorDacl (g_sa.lpSecurityDescriptor, TRUE, NULL, FALSE)) { bRetVal = TRUE; } else { OutputDebugString ("CNDS: cannot set security descriptor DACL\n"); } } else { OutputDebugString("CNDS: cannot initialise security descriptor\n"); } return bRetVal; } //--------------------------------------------------------------------------- void FreeNullDaclSd() { GlobalUnlock (g_hsa); GlobalFree (g_hsa); } //---------------------------------------------------------------------------
If you have to deal with multiple desktops, or terminal server, then you're outside the scope of this article and I refer you to Joe Newcomers very thorough article on this topic, here
Download