Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Win API to determine if an instance of an executable is already running

Tags:

c++

winapi

I need to ensure only 1 instance of my C++ application is running.

Using the Win API how do I;

  1. retrieve the information about my current application? GetCurrentProcess() will give me a HANDLE on my application, how do I retrieve information about it

  2. retrieve a list of all running processes for the user? EnumProcesses() gives a list, but appears to require a pre-allocated buffer, so how do I find out how many processes are currently running?

  3. I need to compare the exe name of my server to the running processes, and raise an error if I find more than one

Note: I cannot use any boost libraries, and I am not interested in using a mutex, seen on similar posts.

like image 946
Marcus MacWilliam Avatar asked Dec 05 '22 09:12

Marcus MacWilliam


2 Answers

You can use the CreateMutex function to create a system-wide named mutex to denote whether your process is running. It will return ERROR_ALREADY_EXISTS if the process is already running:

 (void)::CreateMutex( NULL,
                      TRUE,
                      TEXT( "My_Special_Invokation_Test_Mutex" ) );
 switch ( ::GetLastError() ) {
     case ERROR_SUCCESS:
         // Process was not running already
         break;
     case ERROR_ALREADY_EXISTS:
         // Process is running already
         break;
     default:
         // Error occured, not sure whether process is running already.
         break;
 }

Now, if you insist on not using a mutex, you can use the CreateFile function instead. Make sure to pass zero for the dwShareMode field to get exclusive access semantics, CREATE_NEW for the dwCreationDisposition field (so that you create the file only if it doesn't exist already) and FILE_FLAG_DELETE_ON_CLOSE for the dwFlagsAndAttributes argument so that the file gets deleted once your process is terminated. Something like this:

LPCTSTR lockFileName = ...;
(void)::CreateFile( lockFileName,
                    GENERIC_READ,
                    0,
                    NULL,
                    CREATE_NEW,
                    FILE_FLAG_DELETE_ON_CLOSE,
                    NULL );
switch ( ::GetLastError() ) {
     case ERROR_SUCCESS:
         // Process was not running already
         break;
     case ERROR_FILE_EXISTS:
         // Process is running already
         break;
     default:
         // Error occured, not sure whether process is running already.
         break;
}

See this article about Temporary file generation and usage best practices about how to deal with temporary files safely.

To make a long story short, it's certainly possible to use lock files for your task, but I think it's harder to do it right.

like image 50
Frerich Raabe Avatar answered Dec 06 '22 23:12

Frerich Raabe


Updated version of Nawaz's answer:-

Handle mutex = CreateMutex (0, 0, "SomeUniqueName");

switch (GetLastError ())
{
case ERROR_ALREADY_EXISTS:
  // app already running
  break;

case ERROR_SUCCESS:
  // first instance
  break;

default:
  // who knows what happened!
  break;
}

This does have a security issue, a malicious application could create a mutex called "SomeUniqueName" before your app starts, which would then prevent your app from being run. To counter this, you can name the mutex based on a hash of some constant system parameter (the MAC address for example). The MSDN documentation has this to say about single instance applications:

If you are using a named mutex to limit your application to a single instance, a malicious user can create this mutex before you do and prevent your application from starting. To prevent this situation, create a randomly named mutex and store the name so that it can only be obtained by an authorized user. Alternatively, you can use a file for this purpose. To limit your application to one instance per user, create a locked file in the user's profile directory.

like image 37
Skizz Avatar answered Dec 06 '22 23:12

Skizz