views:

1726

answers:

9

In a Windows environment, I don't want two instances of my program running at the same time.

Related

Is using a Mutex to prevent multiple instances of the same program from running safe?

A: 

You could check if window class is already registered. Take a look at this MSDN entry.

Pablo Santa Cruz
-1. From looking at the link and associated links, I don't believe that the handle returned by RegisterClassEx() is a cross-process entity -- even for the "Application Global classes" (CS_GLOBALCLASS set), you must load the DLL that registers the class in every process, according to http://msdn.microsoft.com/en-us/library/ms633574(VS.85).aspx.
j_random_hacker
+9  A: 

You could create a mutex when the first instance of your application starts. To prevent a second instance all you'd need to do is check if the mutex is being used.

Actually there was a question raised about using mutexes for this purpose here check out JaredPar's answer.

Note: You can use a local mutex if you want the "one instance" to apply only within a user's session (instead of for all users)

RobS
+3  A: 

The best way is to use a mutex. See Using Mutex Objects.

Murray
+8  A: 

I think you need to consider your scenario a bit before going forward. There are many different interpretations of "running the same program" more than once. For instance do you

  1. Once per machine
  2. Once per logon session
  3. Once per user

All of these have different, albeit similar, solutions.

The easiest one to describe is the per machine. In this case you want to create a named Mutex. One startup every program must obtain this mutex, if they are successful they run and hold onto the Mutex for the duration of the process lifetime. Otherwise some other program is running and they exit immediately.

Unforunately this approach also has its drawbacks. If I want to mess up your program, I can create a mutex with the same name. This will prevent your program from running any instance because they are unable to tell who holds the Mutex, just that something is holding the mutex.

JaredPar
I was just thinking the same thing...
RobS
Regarding the "hostile mutex", is that really something you need to be concerned about if you're not writing, say, Word?
Rex M
@Rex M, it's really a question the author would have to answer. I would venture a "no" here. But it's something you should consider when writing the program. If nothing else but for the chance you accidentally do it to yourself.
JaredPar
+1  A: 

Use a mutex, as others have suggested.

That CreateMutex() documentation from MS has a lot of useful information, and specifically addresses the case of using mutexes for preventing more than one instance of a program from running. In particular:

  • Call CreateMutex() with bInitialOwner = FALSE, then call a wait function (e.g. WaitForSingleObject()) to ensure that just one instance acquires the mutex.
  • Consider using a locked file instead if you're worried about denial of service attacks.
j_random_hacker
A: 

At the startup of your program, you can enumerate the processes running on your machine

Then if you see that you're already running, quit

Eric
Does it work if the first two instances are started at the same time?
Liran Orevi
There is a race condition here because process enumeration cannot be atomic. This is why a mutex is a good idea.
RBerteig
-1. I'm sorry but this is a terrible idea. As well as the race condition mentioned by RBerteig, you have the problem of correctly identifying processes -- if you do this by comparing window titles, you can easily get both false positives (other programs with your window title) and false negatives (if your target program's window title changes -- e.g. many programs show the name of the open document in the window title). A better way exists -- use it instead.
j_random_hacker
+1  A: 

this is a class I scripted using boost.interrprocess, I use it to sync between the GUI and CLI versions.

You might find it useful:

#pragma once

#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

using boost::interprocess::windows_shared_memory;
using boost::interprocess::mapped_region;
using boost::interprocess::open_or_create;
using boost::interprocess::read_write;
using boost::interprocess::interprocess_exception;

class CProcessMutex
{

public:
    CProcessMutex()
        : m_region()
        , m_status(false)
    {
        initSharedMemory();
        Increment();
    }

    ~CProcessMutex()
    {
        Decrease();
    }

public:
    int GetCount()
    {
        return m_status ? *(static_cast<unsigned char*>(m_region.get_address())) : 0;
    }

private:
    void initSharedMemory()
    {
        try
        {
            //Create a native windows shared memory object.
            windows_shared_memory shm (open_or_create, "shared_memory", read_write, 1);
            //Map the whole shared memory in this process
            m_region.swap(mapped_region(shm, read_write));
            m_status = true;
        }
        catch(interprocess_exception &ex)
        {
            ex.what();
            m_status = false;
        }
    }

    void Increment()
    {
        if(m_status) (*(static_cast<unsigned char*>(m_region.get_address())))++;
    }
    void Decrease()
    {
        if(m_status) (*(static_cast<unsigned char*>(m_region.get_address())))--;
    }
private:
    mapped_region m_region;
    bool m_status;
};

the usage is simple:

CProcessMutex pm;
size_t current_process_count = pm.GetCount();
if(current_process_count > 1)
{
 ...
}

so you can easily limit how many processes in parallel.

t.g.
+1  A: 

An alternative simple solution is to create a suitably unique global named event (possibly a GUID string) then check for its existence on startup. If it exists then an instance of your app has already been started. If not, you've automatically created the event and can continue to run, e.g.:

// for brevity, a complete set of error handling has been omitted

m_hEvent = CreateEvent(NULL, TRUE, FALSE, szMyUniqueNamedEvent);

switch (GetLastError)
{
    // app is already running
    case ERROR_ALREADY_EXISTS:
    {
        CloseHandle(m_hEvent);

        // now exit
        break;
    }

    // this is the first instance of the app
    case ERROR_SUCCESS:
    {
        // global event created and new instance of app is running,
        // continue on, don't forget to clean up m_hEvent on exit
        break;
    }
}
porkchop
+1. Any atomic operation that creates a global object if it does not yet exist and returns a value indicating whether this creation occurred will do the job.
j_random_hacker
A: 

When you use Qt you can download the QtSingleApplication component.

corné