Somacon.com: Articles on websites & etc.

§ Home > Index > C and C# Programming

Count Instances of Process or Application in C/C++

This article describes how to count the number of instances of a process that are currently running on the system. It is written in C++ for Windows, but could be ported to other systems and languages easily. (Linux, Visual Basic/VB, C, Unix, MacOS) The system just needs to support interprocess semaphores. The idea can be extended to count any resource, such as a thread, file, data structure, or network object.

Semaphores are typically used to limit access to a shared resource to a fixed number of clients. The semaphore itself is just a number that can be incremented and decremented atomically by any process. When it reaches zero though, it causes a client to wait until another client increases the count. In this example, we will just use the semaphore's ability to maintain a count between different processes.

This is mainly written as an alternative to using the EnumWindows API and checking the window title, atom, class name, or other property to find other matching Windows. The problem with the EnumWindows technique is that it is slower, and is more likely to give an invalid count. EnumWindows calls the EnumWindowsProc callback function for every parent window on the system, and there are usually 300 to 500 on a typical Windows system.

To implement the algorithm, create a semaphore at program startup set at a high value. If the semaphore already exists, then just open the existing one. The semaphore can be uniquely identified between processes by assigning it a string GUID. Then, decrement the semaphore's value twice by calling WaitForSingleObject with a zero timeout. Immediately release the semaphore once. Releasing the semaphore increments its value and returns the previous value of the semaphore. The previous value is subtracted from the maximum semaphore value to give the number of instances of the process.

The semaphore should be released at the very end of the program to increment its value back to the original. It should also be closed if the last instance of the program is exiting. This should be done reliably to ensure that the semaphore is not orphaned on a crash. To do this, simply wrap the rest of the program in a try/catch block. Then, place the application count in a global variable so it can be accessed where needed. See the code below.

---------FUNCTION WinMain()-----------
long GlobalApplicationCount;
int ReturnValue;
HANDLE ApplicationCountSemaphore;
const TCHAR szSemaphoreName[] = TEXT("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
const int MaxApplicationCount = 0x0FFFFFFF;

// Create a semaphore to count program instances
ApplicationCountSemaphore = CreateSemaphore(NULL, MaxApplicationCount, 
	MaxApplicationCount, szSemaphoreName);
if(ApplicationCountSemaphore == NULL)
{
	// CreateSemaphore error, use GetLastError()
}

// Wait on the semaphore (possible existing) to decrement its count
WaitForSingleObject(ApplicationCountSemaphore, 0L);
// Wait on the semaphore again
WaitForSingleObject(ApplicationCountSemaphore, 0L);
// Release the semaphore once to get the previous count
ReleaseSemaphore(ApplicationCountSemaphore, 1, &GlobalApplicationCount);
// Calculate the number of processes (including ourself)
GlobalApplicationCount = MaxApplicationCount - GlobalApplicationCount - 1;

// Run the main program function and catch any exceptions
try
{
	ReturnValue = WinMainProtected(hInstance, 
		hInstUnused, lpCmdLine, nCmdShow);
}
catch(...)
{
	MessageBox(NULL, TEXT("An unhandled exception occurred."), 
		NULL, MB_ICONEXCLAMATION | MB_OK);
	ReturnValue = -1;
}

// Release the semaphore
ReleaseSemaphore(ApplicationCountSemaphore, 1, &GlobalApplicationCount);
// Close the semaphore if we are the last process
if(GlobalApplicationCount == MaxApplicationCount - 1)
{
	CloseHandle(ApplicationCountSemaphore);
}

return ReturnValue;
---------END OF WinMain()-----------

Links


Created 2004-11-20, Last Modified 2012-06-25, © Shailesh N. Humbad
Disclaimer: This content is provided as-is. The information may be incorrect.