Arthur
Arthur

Reputation: 3418

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

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.

Upvotes: 32

Views: 26245

Answers (13)

Laura
Laura

Reputation: 1

Sorry to mention this, but none of the methods (ExeName, Mutex, Semaphore, Piped Names, File Mapping on RAM, etc) work at all, the appllication can be run more than once.

First is First: in elevated mode it looks like File Mapping on RAM could work, but with ProcessExplorer you can manually close the handle and that allows to run more than one instance of the APP.

For the rest of methods: Multiple users can copy the app (with different exename) or install it in multiple different locations ... etc.

But the worst part is when the application must be run only once, no matter how many local users are logged.

All methods fails when APP is running in one user account and another user account logon is done, on that other user the app can be run, so no only one instance is running at the same time.

The only way i see to avoid more than once is to force the application to be run only in elevated mode and then it can check if another user is running the app.

In multi-user i see no practical way of not allowing more than one instance ... since the handle to the mapped ram can be closed by third part apps (like process explorer).

I am still searching for a way to allow only one instance per computer.

P.D.: I did not mention running the app inside different virtual machines, since that is directly impossible without a server control method ... and the use of a server is also not mentioned because the app need to be run without network access, runs localy (but multiple users can run it, what is desired is to only run at one user at a time and only once at a time, not two instances running at the same time, no matter same user or different users).

Upvotes: -1

HAMMOU REDOUANE
HAMMOU REDOUANE

Reputation: 13

If You want to stop execution your app more then once in the same time (put the code into *.dpr file of the project). will show a message after second app will be running and stop it instantly .

Forms,
  Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;

{$R *.res}


function ProcessCount(const ExeName: String): Integer;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
  ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
  Result:= 0;
  while Integer(ContinueLoop) <> 0 do begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeName))) then Inc(Result);
    ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;


begin
  if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
    MessageDlg('Application is already running!', mtError, [mbOK], 0);
    Application.Terminate;
  end else begin

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
  end;

end.

Upvotes: 1

Drejc
Drejc

Reputation: 14286

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;

Upvotes: 19

Rob Kennedy
Rob Kennedy

Reputation: 163317

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.

Upvotes: 39

Kluge
Kluge

Reputation: 3717

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);

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1502086

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.

Upvotes: 5

g2mk
g2mk

Reputation: 507

Controlling the number of application instances:

http://delphi.about.com/od/windowsshellapi/l/aa100703a.htm

Upvotes: 1

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-

Upvotes: 0

mghie
mghie

Reputation: 32334

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.

Upvotes: 2

Edin Omeragic
Edin Omeragic

Reputation: 1968

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;

Upvotes: 2

ahanson
ahanson

Reputation: 2178

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.

Upvotes: -1

user54808
user54808

Reputation:

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.

Upvotes: 1

utku_karatas
utku_karatas

Reputation: 6315

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

Upvotes: 17

Related Questions