Disallowing Multiple Instances of Some Types
of Applications
The following code example shows how to limit your application to running only a single instance under Terminal Services. The code is Win32-compatible, so it can run on all platforms. The key is to use a mutex (mutual exclusion) object to determine if the application is already running. The old practice of using a window handle does not work under Terminal Services, because window handles are specific to a session, thus there are no system global window handles. The code uses the Terminal Services multisession object manager Global\ prefix to force the mutex into the system-wide global name space.
//
// Global Variables
//
BOOL g_fIsTerminalServer = FALSE;
TCHAR g_szAppName[] = TEXT("Generic");
HANDLE g_hAppRunningMutex = NULL;
//
// IsAppAlreadyRunning
//
// This routine check to see if the application is already running.
// The fOnePerSystem flag is used for Terminal Server, thus allowing
// you to limit the running instances to one per system or one per
// user session.
//
// NOTE: The g_hAppRunningMutex handle must remain open while your
// application is running.
//
BOOL IsAppAlreadyRunning( PCTSTR pszAppName, BOOL fOnePerSystem )
{
TCHAR szMutexName[MAX_PATH];
ASSERT(pszAppName != NULL);
ASSERT(g_hAppRunningMutex == NULL);
// Create a mutex in the global name space to see if an instance
// of this application is already running. If so, exit the app.
*szMutexName = TEXT('\0');
if (fOnePerSystem && g_fIsTerminalServer) {
//
// We're running on Terminal Server, so prefix the mutex name
// with Global\ to force it into the system global name space
//
lstrcpy(szMutexName, TEXT("Global\\"));
}
lstrcat(szMutexName, g_szAppName);
lstrcat(szMutexName, TEXT(" is running"));
g_hAppRunningMutex = CreateMutex(NULL, FALSE, szMutexName);
if (g_hAppRunningMutex != NULL) {
//
// Make sure we are the only process with a handle to our named mutex.
//
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// The app is already running
CloseHandle(g_hAppRunningMutex);
g_hAppRunningMutex = NULL;
}
return (g_hAppRunningMutex == NULL);
}
//
// Cleanup routine. This should be called right before the application
// exists. Once this routine closes the g_hAppRunningMutex handle, then
// another instance of your application will be allowed to run.
//
VOID LetAnotherInstanceRun( VOID )
{
if (g_hAppRunningMutex != NULL) {
CloseHandle(g_hAppRunningMutex);
g_hAppRunningMutex = NULL;
}
}
//
// Example of how these routined would be called from WinMain
//
WinMain( ... ) {
//
// First, determine if we're running on a TS enabled system.
//
g_fIsTerminalServer = IsTerminalServicesEnabled();
//
// Check to see if another instance is running
//
if (IsAppAlreadyRunning(g_szAppName, TRUE)) {
// Display message box to user to let them know
// that only one instance is allowed.
return;
}
....
//
// Close the App's mutex, thus allowing another instance
// to run.
//
LetAnotherInstanceRun();
}
|