|
INPRISE Online And ZD Journals Present:
Over the past few months, a few people on the CPB-Thread listserv have asked how to prevent more than one instance of an application from being started. (To subscribe to CPB-Thread, visit www.zdjournals.com/cpb.) Several people have worked very hard on a variety of answers to this question. It seems, though, that the simplest solution is one suggested by members of Borland's TeamB on their news server: a named mutex. As you know, Windows 95 provides a number of built-in functions for running multiple tasks and threads within a task. Accordingly, a group of Synchronization functions is available to ensure that your tasks and threads are able to work together effectively. One of the more common problems in a multitasking environment is resource sharing. If you're using a resourcefor example, a serial portyou don't want somebody else to start using it before you're finished. The standard solution to this problem is for you to get a mutual exclusion lock (mutex) on the resource. If you're able to get the lock, you can use the resource. If, while trying to lock the resource, you find that somebody else has ityou must wait. In this article, we'll build a small and very simple function to return true if an instance of a program is already running. To do this, we'll use a simple named mutex. (You can download the code from this article at www.zdjournals.com/cpb.) Let's start by looking at how you can use a mutex.
Using a named mutex If you create a resource that can be used by only one caller at a time, you'll probably also create a mutex for it. In this case, your callers try to open the mutex to see if the resource exists. Once they have a valid handle to the mutex, they use wait functions to gain ownership of the resource and start using it. Wait functions sleep until a mutex isn't owned, then take ownership of it and use the resource. (You can optionally place a time limit on a wait function.) Eventually, the caller will release the mutex, marking it not owned and available to the next caller. In this way, all callers wait to take ownership of the resource when they need it and release it when they're finished. If a caller has no further need for a resource, the mutex handle can be closed. Once a mutex exists, any tasks trying to create it again will get a handle to it and an error already exists error. If a task ends, all the mutex handles that it owns are closed. When all tasks have closed their handles to a mutex, it's destroyed. Therefore, a single call to the CreateMutex() function is all you need to find out if an instance of an application is already running!
Using CreateMutex() If the returned HANDLE is null, something undesirable happened. In any case, GetLastError() should return zero to indicate that the mutex was created. A value of ERROR_ALREADY_EXISTS indicates that the mutex already exists. Use SysErrorString() to translate the other error codes into English. By now you've probably realized that there really isn't much to ityou can very easily detect an existing instance of an application using this method. Listing A shows the source code for one way to do it.
Listing A: Detecting another instance of an application //-------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop //-------------------------------------------- USEFORM("OneOnlyForm.cpp", Form1); USERES("OneOnly.res"); //-------------------------------------------- // the name of the mutex for this program const char *MutexName = "OneOnlyDemo"; //-------------------------------------------- HANDLE CheckInstance( const char *Name ) { // 1st: create mutex. Request ownership. HANDLE Mutex = CreateMutex(NULL,true,Name); // Next, error result - should be zero int r = GetLastError(); // if r != 0, probably ERROR_ALREADY_EXISTS if ( r != 0 ) return 0; // disaster or another instance return Mutex; // else, return the handle. } //-------------------------------------------- WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR, int) { HANDLE Mutex = CheckInstance( MutexName ); if ( !Mutex ) { MessageBox(HInstance, "Another Instance is running!", "Sorry", MB_OK ); ReleaseMutex( Mutex ); return 1; }; try { Application->Initialize(); Application->CreateForm(__classid( TForm1),&Form1); Application->Run(); } catch (Exception &exception) { Application->ShowException(&exception); } return 0; } //--------------------------------------------
Wrap up Sam Azer is a freelance systems analyst who's been based in Montreal, Canada, since 1982. He's a Borland C++ and C++Builder fan and an avid photographer. You can reach Sam at Sam@AzerTech.com. His Web site, which is generally under construction, is at http://AzerTech.com. Back to Top Back to 1998 Index of Articles Copyright © 1998, Ziff-Davis Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of Ziff-Davis Inc. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited. |