Click here to Skip to main content
15,879,095 members
Articles / Desktop Programming / MFC
Article

Limiting the Number of Instances Running

Rate me:
Please Sign up or sign in to vote.
4.38/5 (19 votes)
6 Dec 20055 min read 72.2K   608   39   20
Describes several methods to show how to limit the number of running instances of an application.

Introduction

This article describes six methods which can be used to limit the number of running instances of a given application. It starts with describing an old method which was used in the Win16-era and not useful today. That is why that method has ‘zero’ as its name. The others show different principles of achieving the main goal.

METHOD 0: Does Nothing Nowadays

The entry point for both Windows-based and Win32-based applications is WinMain (or wWinMain). This function has four parameters, two of which are of the type HINSTANCE. The first one represents the instance of a given application and the second one represents the instance of a previous application running, if any. This second parameter is NULL in Win32 hence it does nothing. In Win16, one of its usages was determining the existence of a previous instance of a given application. One might use it as follows:

int WinMain(HINSTANCE hInstance,       /* Handle of current instance  */ 
        HINSTANCE hPrevInstance,   /* Handle of previous instance */ 
        LPSTR lpszCmdLine,
        int nCmdShow
)
{
    if (hPrevInstance != NULL)
    {
        return(0);
    }
    // The first instance
}

This method is totally obsolete. Several methods that may be used in Win32 are presented below.

METHOD 1: Mutex as a Named Object

Mutexes may be created as named or unnamed objects depending on the last parameter of the CreateMutex function. If taking a null string, it creates an unnamed mutex, otherwise it creates a named mutex. This named mutex is able to be recognized by another application, of course, by its name. So, named mutexes can be used to limit the number of instances running of a given application. The following code is to be placed in the WinMain function (or in the InitInstance method if MFC is on):

// In WinMain(..)
HANDLE hMutex = CreateMutex(NULL, FALSE, 
                   "{FA531CC1-0497-11d3-A180-00105A276C3E}");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
   // There is already an instance of this application running.
   return 0;
}

// This is the first instance of this application running.

// Before exiting, close the object.
CloseHandle(hMutex);

Usually, a name is passed as a GUID to guarantee its uniqueness. But you may name a mutex whatever you desire.

Mutexes are not the only objects that are able to carry names. There are other synchronization objects that can be used instead. Nevertheless, mutexes’ case is a classical representation.

The next method is also a named object’s one. It uses a memory-mapped file as a named object. The main difference between the map-files’ method and the mutexes’ method is that the latter cannot be used in Win16, but the former can. Perhaps, because of that, the map-files’ method is shown separately.

METHOD 2: Memory-mapped File as a Named Object

In the WinMain function (or in the InitInstance method if MFC is on), we can put the following code which demonstrates how to use a named map-file to limit the number of instances running of a given application:

// In WinMain(..)
HANDLE hMap = CreateFileMapping( (HANDLE) 0xffffffff,
                              NULL,
                              PAGE_READONLY,
                              0,
                              32,
                              "{FA531CC1-0497-11d3-A180-00105A276C3E}" );
if(hMap)
{
   if( GetLastError() == ERROR_ALREADY_EXISTS )
   {
       // Display something that tells the user
       // the app is already running.
      return 0;
   }
}
else
{
    // Some other error; handle error.
   return 1;
}

All methods shown so far have a restriction; they allow only one instance to be run. Theoretically, it is possible to limit the number of instances of a given application by two or more instances. The next three methods show how to do it. Besides, they may be considered alternatives to the previous ones.

METHOD 3: Shared Sections

A nice method is to make use of shared sections to store a global variable that can be recognized by all instances of a given application. The following macros are to be placed before the WinMain function’s definition (or the InitInstance method if MFC is on):

#pragma data_seg("MyShared")
volatile UINT g_nInstancesRunning = 0;
#pragma data_seg()

#pragma comment(linker, "/Section:MyShared,RWS")

The code above declares a shared section named ‘MyShared’ and puts a global variable in it of type UINT. The keyword ‘volatile’ tells the compiler not to try optimizing the variable’s behavior. The ‘comment’ macro tells the linker to prepare the ‘MyShared’ section to be Readable, Writable and Shared. Now, in the WinMain (or InitInstance), we may check for the variable's value. For this purpose, we would like to use the InterlockedExchangeAdd function; this function atomically adds a LONG value to its first parameter and returns its previous value. For example, if we want to set a limit number of 5, the following code will do:

// In WinMain(..)
if (5 == ::InterlockedExchangeAdd((PLONG) &g_nInstancesRunning, 1))
{
    return FALSE;
}

But, it is necessary to reduce the value of the variable before WinMain exits (ExitInstance if MFC is on):

::InterlockedExchangeAdd((PLONG) &g_nInstancesRunning, -1);

METHOD 4: One Mutex per Instance

Why not use mutexes to set a limit number to not only 1, but also 2 or more? In this case, a nice algorithm can be developed to help. The essence of this method is to prepare one named mutex per instance running until the maximum number reaches. I’ve built a C++ class, CInstanceLimit, to encapsulate the code. Simply declare an object globally and use it in the WinMain function (or InitInstance if MFC is on). By the way, the destructor will free all resources captured; you need not worry about it. The constructor takes two parameters; the first is the maximum number of instances allowed to run (the default is 1), and the second is a unique string, mostly a GUID (the default is the name of the class). For example, we may use it like so:

CInstanceLimit g_limit(5); // the limit number is 5

// In WinMain(..)
if (g_limit.Limit())
{
    return FALSE;
}

The source code of this class is to be downloaded.

METHOD 5: Registry

Another idea is to use the Registry to store the current number of instances running. Every time an instance is getting run, the value in the Registry must be incremented, and before exiting, the same value in the Registry must be decremented. This technique is demonstrated by a C++ class, CInstanceRegLimit. This class is similar to the previous method’s class. But this one is used only by MFC applications, as it uses MFC’s services to access the Registry. To use the class, we need to declare its object as a member-variable of the CWinApp derived class in order to make the object’s destructor get called before ‘theApp’ is destroyed to update the Registry correctly. Then, in the InitInstance, we have:

// In InitInstance
SetRegistryKey(_T("My Company Name"));

if (m_limit.Limit())
{
    return FALSE;
}

Note, the ‘if’ instruction must be placed after the call to the SetRegistryKey to ensure that the data will be stored in the Registry rather than in an INI file. Of course, if you want to use INI files, simply remove the SetRegistryKey call.

The source code of this class is to be downloaded.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer 13
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIs there any problem if process crashes? Pin
Geckops8-Aug-06 23:31
Geckops8-Aug-06 23:31 
AnswerRe: Is there any problem if process crashes? Pin
jayesh_kitts2-Apr-07 2:26
jayesh_kitts2-Apr-07 2:26 
GeneralGood job! Pin
Vaga15056-Jul-06 3:15
Vaga15056-Jul-06 3:15 
GeneralGood article Pin
lano110612-Dec-05 13:20
lano110612-Dec-05 13:20 
GeneralMethod 1.5 - Use a named semaphore object Pin
Neal Stublen12-Dec-05 4:11
Neal Stublen12-Dec-05 4:11 
GeneralAbout METHOD 3: Shared Sections Pin
gyb9987-Dec-05 14:38
gyb9987-Dec-05 14:38 
GeneralRe: About METHOD 3: Shared Sections Pin
Arman S.8-Dec-05 0:37
Arman S.8-Dec-05 0:37 
Generalyet another instance counter (yaic) Pin
Harm Salomons7-Dec-05 10:35
Harm Salomons7-Dec-05 10:35 
GeneralRe: yet another instance counter (yaic) Pin
Arman S.8-Dec-05 0:33
Arman S.8-Dec-05 0:33 
GeneralMethod 5 Pin
Blake Miller6-Dec-05 9:34
Blake Miller6-Dec-05 9:34 
GeneralRe: Method 5 Pin
gxdata6-Dec-05 17:22
gxdata6-Dec-05 17:22 
GeneralRe: Method 5 Pin
Blake Miller7-Dec-05 4:26
Blake Miller7-Dec-05 4:26 
QuestionRe: Method 5 Pin
wittend12-Dec-05 12:10
wittend12-Dec-05 12:10 
AnswerRe: Method 5 Pin
Blake Miller12-Dec-05 12:42
Blake Miller12-Dec-05 12:42 
GeneralRe: Method 5 Pin
Rage7-Dec-05 0:09
professionalRage7-Dec-05 0:09 
GeneralRe: Method 5 Pin
Blake Miller7-Dec-05 4:30
Blake Miller7-Dec-05 4:30 
GeneralRe: Method 5 Pin
Arman S.8-Dec-05 0:27
Arman S.8-Dec-05 0:27 
You might have mentioned this is not a good idea because if your process is terminated, your 'cleanup' of the registry will not take place.

Of course, Method 5 is not secure.

You did not mention the classic 'FindWindow' technique, at least as method -1

Really. Honesly, I don't like that method and I think it is so well-known and unsucceeded that is not worth '-1'.;)

Actually, I got to thinking, what if you opened the registry key as volatile, or did something more clever, like openend SUBKEYS volatile (for multiple instance support), then as each process might be terminated, the registry key would be closed and evaporated. That might make #5 actually work.

Thanks. I think I may use comments when updating the article.


--
======
Arman
GeneralRe: Method 5 Pin
Blake Miller8-Dec-05 8:55
Blake Miller8-Dec-05 8:55 
GeneralMethod 1 Pin
skornel6-Dec-05 7:56
skornel6-Dec-05 7:56 
GeneralRe: Method 1 Pin
Arman S.8-Dec-05 0:12
Arman S.8-Dec-05 0:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.