How can I tell if another instance of my program is already running?

24,118

Solution 1

You can create a Semaphore and stop execution (put the code into your *.dpr file) and bring you running application to the screen.

var
  Semafor: THandle;

begin
  { Don't start twice ... if already running bring this instance to front }
  Semafor := CreateSemaphore(nil, 0, 1, 'MY_APPLICATION_IS_RUNNING');
  if ((Semafor <> 0) and { application is already running }
     (GetLastError = ERROR_ALREADY_EXISTS)) then 
  begin
    RestoreWindow('TMyApplication');
    CloseHandle(Semafor);
    Halt;
  end;

  Application.CreateForm(....);    
  Application.Initialize;
  Application.Run;
  CloseHandle(Semafor);
end;

EDIT (added the RestoreWindow method):

The aFormName is the name of your main form class in your application.

procedure RestoreWindow(aFormName: string);
var
  Wnd,
  App: HWND;    
begin
  Wnd := FindWindow(PChar(aFormName), nil);
  if (Wnd <> 0) then 
  begin { Set Window to foreground }
    App := GetWindowLong(Wnd, GWL_HWNDPARENT);
    if IsIconic(App) then 
      ShowWindow(App, SW_RESTORE);

    SetForegroundwindow(App);
  end;
end;

Solution 2

As Jon first suggested, you can try creating a mutex. Call CreateMutex. If you get a non-null handle back, then call GetLastError. It will tell you whether you were the one who created the mutex or whether the mutex was already open before (Error_Already_Exists). Note that it is not necessary to acquire ownership of the mutex. The mutex is not being used for mutual exclusion. It's being used because it is a named kernel object. An event or semaphore could work, too.

The mutex technique gives you a Boolean answer: Yes, there is another instance, or no, there is not.

You frequently want to know more than just that. For instance, you might want to know the handle of the other instance's main window so you can tell it to come to the foreground in place of your other instance. That's where a memory-mapped file can come in handy; it can hold information about the first instance so later instances can refer to it.

Be careful when choosing the name of the mutex. Read the documentation carefully, and keep in mind that some characters (such as backslash) are not allowed in some OS versions, but are required for certain features in other OS versions.

Also remember the problem of other users. If your program could be run via remote desktop or fast user switching, then there could be other users already running your program, and you might not really want to restrict the current user from running your program. In that case, don't use a global name. If you do want to restrict access for all users, then make sure the mutex object's security attributes are such that everyone will be able to open a handle to it. Using a null pointer for the lpSecurityAttributes parameter is not sufficient for that; the "default security descriptor" that MSDN mentions gives full access to the current user and no access to others.

You're allowed to edit the DPR file of your program. That's usually a good place to do this kind of thing. If you wait until the OnCreate event of one of your forms, then your program already has a bit of momentum toward running normally, so it's clumsy to try to terminate the program at that point. Better to terminate before too much UI work has been done. For example:

var
  mutex: THandle;
  mutexName: string;
begin
  mutexName := ConstructMutexName();

  mutex := CreateMutex(nil, False, PChar(mutexName));

  if mutex = 0 then
    RaiseLastOSError; // Couldn't open handle at all.

  if GetLastError = Error_Already_Exists then begin
    // We are not the first instance.
    SendDataToPreviousInstance(...);
    exit;
  end;
  // We are the first instance.

  // Do NOT close the mutex handle here. It must
  // remain open for the duration of your program,
  // or else later instances won't be able to
  // detect this instance.

  Application.Initialize;
  Application.CreateForm(...);
  Application.Run;
end.

There's a question of when to close the mutex handle. You don't have to close it. When your process finally terminates (even if it crashes), the OS will automatically close any outstanding handles, and when there are no more handles open, the mutex object will be destroyed (thus allowing another instance of your program to start and consider itself to be the first instance).

But you might want to close the handle anyway. Suppose you chose to implement the SendDataToPreviousInstance function I mentioned in the code. If you want to get fancy, then you could account for the case that the previous instance is already shutting down and is unable to accept new data. Then you won't really want to close the second instance. The first instance could close the mutex handle as soon as it knows it's shutting down, in effect becoming a "lame duck" instance. The second instance will try to create the mutex handle, succeed, and consider itself the real first instance. The previous instance will close uninterrupted. Use CloseHandle to close the mutex; call it from your main form's OnClose event handler, or wherever else you call Application.Terminate, for example.

Solution 3

The all-mighty JVCL has a component for this purpose. See "TJvAppInstances".

Solution 4

You create a system mutex.

I don't have Delphi code, but here's C++ code:

HANDLE Mutex;

const char MutexName[] = "MyUniqueProgramName";

Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName);

if (Mutex)
     throw Exception("Program is already running.");
else
     Mutex = CreateMutex(NULL, true, MutexName);

Solution 5

The normal solution is to create a named, system-wide mutex.

  • If you manage to create it, you're the one running application.
  • If you don't, you know there's a different one.

EDIT:

I haven't provided code as I don't know Delphi. I can provide C# code if that would be helpful though.

Share:
24,118

Related videos on Youtube

Blair Houghton
Author by

Blair Houghton

Updated on July 09, 2022

Comments

  • Blair Houghton
    Blair Houghton almost 2 years

    How do i tell if one instance of my program is running? I thought I could do this with a data file but it would just be messy :(

    I want to do this as I only want 1 instance to ever be open at one point.

  • Rob Kennedy
    Rob Kennedy over 15 years
    You have a race condition there. Always call CreateMutex, not OpenMutex. Then use GetLastError to find out who won the race.
  • Kluge
    Kluge over 15 years
    @Rob Kennedy, You're right. The code could fail of two instances of the program were started almost instantly. Your suggestion is correct.
  • Blair Houghton
    Blair Houghton over 15 years
    What units does this use HWND and findwindow were not recognised. also will this work if my "window" is hidden into the icontray?
  • Sam
    Sam over 15 years
    Do you need to close the mutex handle when the application exits?
  • mghie
    mghie over 15 years
    No, as a mutex like all other OS resources is freed / released / whatever when the owning process terminates. That is also the great plus of this solution compared with temporary files that may still exist after the application has crashed.
  • Alex
    Alex over 15 years
    It will need "Windows". This is a useful addition to the Mutex, in that you might bring the previous window to the front. But if the user opens your app twice in succession, the first may not have opened its window yet and therefore it may be missed.
  • Rob Kennedy
    Rob Kennedy over 15 years
    Einstein, yes, a global mutex is good if that's what Arthur wants. Based on one of his previous questions, though, I don't think it is. And as I recall, pre-Win2k didn't allow backslashes in the name, so you can't necessarily use the same name all the time, either.
  • Rob Kennedy
    Rob Kennedy over 15 years
    Sam, the OS will do it for you. But you might want to close it earlier. If the current instance is closing, it won't be able to accept messages from another instance. At that point, it might be better for the "new" instance to assume its role as "the" instance and just left the first instance die.
  • mghie
    mghie over 15 years
    Rob, I just re-read your answer, and IMHO you should clarify the "could be run on Terminal Server" part. Many devs will probably dismiss this as not being important for them, when in fact fast user switching would be enough to trigger the problem.
  • Blair Houghton
    Blair Houghton over 15 years
    sorry for being a noob but what units does this example use except from "windows" ?
  • Blair Houghton
    Blair Houghton over 15 years
    reading up on "procedure RestoreWindow( WinHandle : HWND );" as i need the handle of the aplicaton that was running first i need to get the handle of the aplication that has the hold on the semaphore. not sure if this is a new question or a extention
  • Drejc
    Drejc over 15 years
    Ups ... forgot to add the RestoreWindow method, ... will edit the answer
  • Rob Kennedy
    Rob Kennedy over 15 years
    It uses Windows and Forms, plus whatever units contain the code you write for providing ConstructMutexName and SendDataToPreviousInstance. If you want someone to write those for you, post new questions: "How do I construct a mutex name?" and "How do I send data to another instance of my program?"
  • Blair Houghton
    Blair Houghton over 15 years
    Dont know if im getting the AformName wroung but it does not open up the old instance.
  • Drejc
    Drejc over 15 years
    It works on my project. I have a form named TMonexMainFrm and it is the first form created in Application.CreateForm(TMonexMainFrm, MonexMainFrm); And I have a variable var MonexMainFrm : TMonexMainFrm; This should work.
  • Drejc
    Drejc over 15 years
    Then I restore it by calling; RestoreWindow('TMonexMainFrm');
  • Blair Houghton
    Blair Houghton over 15 years
    Thanks the var realy fixes this, it works just as you said, only thing is that my app is hidden, but this does work if window is open in the background.
  • Drejc
    Drejc over 15 years
    Hmmm ... maybe the FindWindow (or some similar) method can be used to show hidden forms. Or you can list all processes find your process and extract the form name (just an idea)
  • Rob Kennedy
    Rob Kennedy over 15 years
    I think we have a case of scope creep. You're dwelling a lot on the RestoreWindow portion of the answer. If you want more details about that, I advise you to find or ask another question: "How do I make one instance of my program activate another?"
  • Server Overflow
    Server Overflow over 6 years
    this answer should be deleted.
  • Server Overflow
    Server Overflow over 6 years
    FindWindow should receive a pwidechar instead of pChar.
  • Server Overflow
    Server Overflow over 6 years
    I think you can also do something like: WinApi.Windows.SendMessage(Wnd, UM_ENSURERESTORED, 0, 0); { Similar: delphidabbler.com/articles?article=13&part=2 }