Solved

Is my application currently running?

Posted on 2004-04-17
11
862 Views
Last Modified: 2010-04-05
I am trying to ensure that only one instance of my Delphi 3 application is running in memory at any given time, on one computer.   I tried using the following code, but it is unreliable...

// The following code ensures that your .exe will only run once:
{Searches table to see if the program is already running}
if GlobalFindAtom('PROGRAM_RUNNING') = 0 then begin
      { If not found then add it }
      atom := GlobalAddAtom('PROGRAM_RUNNING')
end else begin
      { If program is already running the show message and halt }
      Halt;
end;

...where "atom" is defined as a global integer.

The problem is that if the program crashes, it is impossible to relaunch the application without triggering the "Halt" procedure.  Evidently the Atom is not cleared up when the application has a fatal exception that terminates the program.

Is there a more reliable method of ensuring that my application is only in memory once?

Thanks.
0
Comment
Question by:Monroe406
  • 5
  • 5
11 Comments
 
LVL 26

Assisted Solution

by:Russell Libby
Russell Libby earned 40 total points
ID: 10850272

Yes, use a named event or named mutex. These handles are tied to the process, and will be closed when the process dies. (unlike the atom table, where a GlobalDeleteAtom, or a reboot is required to clear the atom)

Regards,
Russell
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10850309
0
 

Author Comment

by:Monroe406
ID: 10850371
>> unlike the atom table, where a GlobalDeleteAtom, or a reboot is required to clear the atom

Well, I forgot to add that on my main form's OnDestroy event I do have a GlobalDeleteAtom call...

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
      {Removes the item from the table so it can be run again}
      GlobalDeleteAtom(atom);
end;

It's simply not reliable.
0
ScreenConnect 6.0 Free Trial

Discover new time-saving features in one game-changing release, ScreenConnect 6.0, based on partner feedback. New features include a redesigned UI, app configurations and chat acknowledgement to improve customer engagement!

 

Author Comment

by:Monroe406
ID: 10850383
>> use a named event or named mutex

I've tried the following using a Mutex, but is does not work.  I can launch dozens of instances of the same program with the following failed code...

public
        { Public declarations }
        Mutex: THandle;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
      Mutex := CreateMutex(nil, True,
            PChar(ExtractFileName(Application.ExeName)));
      if Mutex = 0 then
      begin
        Application.ShowMainForm := False;
        Application.Terminate; // See FormDestroy for house cleaning
      end;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
      if Mutex <> 0 then ReleaseMutex(Mutex);
end;
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10850418
this is pseudocode, I don't have delphi on my current computer so I don't want to post buggy code:

 >> use a named event or named mutex

I've tried the following using a Mutex, but is does not work.  I can launch dozens of instances of the same program with the following failed code...

OnCreate Event()
begin
   Mutex := OpenMutex(mutexname);
   if Mutex = 0 then
     begin
       Mutex = CreateMutex(mutexname);
        if Mutex <> 0 then
          { continue executing app }
     end  
  else
    begin
      ReleaseMutex(Mutex);
      {terminate application}
    end;      
end;

OnDestroy Event()
begin
  if Mutex <> 0 then ReleaseMutex(Mutex);
end;

On the other things it's a better idea to do the mutex checking on the .dpr file.

Right there:

begin
 {check mutex here}
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
0
 

Author Comment

by:Monroe406
ID: 10850428

I think I found a solution...

If I add a few more conditionals, then the second instance of the application will be caught and terminated.  Instead of using just "if Mutex = 0 then..." I find that the following conditional statement works...

if ( GetLastError() = ERROR_ALREADY_EXISTS ) or
        ( WaitForSingleObject(Mutex,100) = WAIT_TIMEOUT ) or
        ( Mutex = 0 ) then begin
        Application.ShowMainForm := False;
        Application.Terminate; // See FormDestroy for house cleaning
end;
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10850440
You should not wait for the Mutex, that will make your application wait (while loaded in memory) for the mutex to be released (wait forthe other instance(s) to be closed).
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10850457
OH! I didn't see your were waiting just for 100 milliseconds. Anyway it's better to do the checking on the .dpr so the main form is never created and the ReleaseMutex always happens.
0
 
LVL 9

Accepted Solution

by:
Cayce earned 60 total points
ID: 10850475
Mutex: THandle;
begin
  try
    {create for mutex in here}
    if ( GetLastError() = ERROR_ALREADY_EXISTS ) or
      ( WaitForSingleObject(Mutex,100) = WAIT_TIMEOUT ) or
       ( Mutex = 0 ) then
         begin
                 Application.ShowMainForm := False;
          end
      else
          begin
             Application.Initialize;
             Application.CreateForm(TForm1, Form1);
             Application.Run;
          end;
  finally
    ReleaseMutex(Mutex);
  end;
end.
0
 

Author Comment

by:Monroe406
ID: 10851017
>> Mutex: THandle;


You cannot put the above line by itself in a DPR.  The source code will not compile...

There is something you've left out of your above example.
0
 

Author Comment

by:Monroe406
ID: 10851067
The following needs to be added to your example to work...

uses
      Sysutils,
      Windows,
..

var
      Mutex: THandle;

...
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question