views:

2476

answers:

10

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.

Edit: Re-tagged

+3  A: 

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.

Jon Skeet
+5  A: 

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);
Kluge
You have a race condition there. Always call CreateMutex, not OpenMutex. Then use GetLastError to find out who won the race.
Rob Kennedy
@Rob Kennedy, You're right. The code could fail of two instances of the program were started almost instantly. Your suggestion is correct.
Kluge
+11  A: 

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

utku_karatas
+25  A: 

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.

Rob Kennedy
Do you need to close the mutex handle when the application exits?
Sam
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.
mghie
Highly recommend prepending "Global\\" to the mutex name so that the mutex is globally scoped. If you login as another session or run the application as a service mutexes that are not global can be created in separate non-colliding namespaces.
Einstein
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
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.
Rob Kennedy
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.
mghie
sorry for being a noob but what units does this example use except from "windows" ?
Arthur
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?"
Rob Kennedy
+1  A: 

I would say that there are several different strategies that you can employ. But the easiest one (and not platform specific) is the one you yourself suggested, namely to, at the start of the program check to see if there is a lock file created in a set, specific location. If this lock file exists, then another instance is already running, if it doesn't exist, then there is not another instance running. When your program exits, you delete the lock file.

However, employing this strategy you have another problem, what happens if your program crashes? The lock file still remains, and this specific case need to be handled.

Another strategy is the system-wide mutex solution, where you register your presence within the operating system (or it's also plausible that this is done automagically). When a second instance then tries to start, it checks if there's already a process active with a specific ID. If it already exists, the second process chooses not to start, and optionally brings the first process' window in focus (if the process in question owns a window that is).

However, this strategy is platform specific, and the implementation will differ from platform to platform.

jimka
A: 

In the past, I've used a socket to prevent multiple instances from running at the same time. If the socket is in use, don't continue the program, if it's available let everything run as normal.

tgm
+1  A: 

You can simply use FindWindow windows api function. In delphi class name of the window is the same as class name, you can redefine class name by overriding CreateParams function. To check if window exists add code before main window is created , before Application.Initialize;

Program test
var 
  handle :HWND;
begin
  handle := FindWindow('TMySuperApp', nil);

  if IsWindow(handle) then
  begin 
       //app is running
       exit;
  end.

  Application.Initialize;
  Application.CreateForm(TMySuperApp, SuperApp);
  Application.Run;
end;
Edin
What units does this use HWND and findwindow were not recognised. also will this work if my "window" is hidden into the icontray?
Arthur
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.
mj2008
+2  A: 

I'd like to add one point to the excellent answer by Rob Kennedy (apart from the fact that it would be best to make a function out of his code instead of copying everything into the DPR file. You only need two parameters, the name of the mutex, and a boolean whether the mutext should be per-user or system-wide).

The answer does not give much consideration to the naming of the mutex. If you expect your program to be installed via Inno Setup (and maybe other setup tools too) you should choose the name carefully, as the mutex can be used to have the setup program check whether the application is currently running, and alert the user that they should close all instances of the application. If you choose to allow one instance of the program per user you may need to create a second system-wide mutex too, as the setup may need to have no running instances of the application at all in order to be able to replace files. The name that is to be used for synchronization with an InnoSetup installer must be hard-coded.

mghie
+2  A: 

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;
Drejc
this is greate but i cant get "RestoreWindow('TMyApplication')" to workdo i have to implement this or do i need to use a unit i am currently not using
Arthur
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
Arthur
Ups ... forgot to add the RestoreWindow method, ... will edit the answer
Drejc
Dont know if im getting the AformName wroung but it does not open up the old instance.
Arthur
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
Then I restore it by calling; RestoreWindow('TMonexMainFrm');
Drejc
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.
Arthur
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)
Drejc
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?"
Rob Kennedy
A: 

See this unit (using CreateMutex): UiApp

Additionally at this page, you can read the advantages and disadvantages for to this work with differents methods (mutex, FindWindows,...).

This unit have the solution to activate the previos instance of the application when this is detected.

Regards and excuse-me for my bad english.


Neftalí -Germán Estévez-

Neftalí