How can I tell if another instance of my program is already running?
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.
Related videos on Youtube
Blair Houghton
Updated on July 09, 2022Comments
-
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 over 15 yearsYou have a race condition there. Always call CreateMutex, not OpenMutex. Then use GetLastError to find out who won the race.
-
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 over 15 yearsWhat units does this use HWND and findwindow were not recognised. also will this work if my "window" is hidden into the icontray?
-
Sam over 15 yearsDo you need to close the mutex handle when the application exits?
-
mghie over 15 yearsNo, 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 over 15 yearsIt 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 over 15 yearsEinstein, 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 over 15 yearsSam, 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 over 15 yearsRob, 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 over 15 yearssorry for being a noob but what units does this example use except from "windows" ?
-
Blair Houghton over 15 yearsreading 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 over 15 yearsUps ... forgot to add the RestoreWindow method, ... will edit the answer
-
Rob Kennedy over 15 yearsIt 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 over 15 yearsDont know if im getting the AformName wroung but it does not open up the old instance.
-
Drejc over 15 yearsIt 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 over 15 yearsThen I restore it by calling; RestoreWindow('TMonexMainFrm');
-
Blair Houghton over 15 yearsThanks 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 over 15 yearsHmmm ... 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 over 15 yearsI 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 over 6 yearsthis answer should be deleted.
-
Server Overflow over 6 yearsFindWindow should receive a pwidechar instead of pChar.
-
Server Overflow over 6 yearsI think you can also do something like: WinApi.Windows.SendMessage(Wnd, UM_ENSURERESTORED, 0, 0); { Similar: delphidabbler.com/articles?article=13&part=2 }