• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 896
  • Last Modified:

Is my application currently running?

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
Monroe406
Asked:
Monroe406
  • 5
  • 5
2 Solutions
 
Russell LibbySoftware Engineer, Advisory Commented:

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
 
Monroe406Author Commented:
>> 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
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
Monroe406Author Commented:
>> 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
 
CayceCommented:
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
 
Monroe406Author Commented:

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
 
CayceCommented:
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
 
CayceCommented:
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
 
CayceCommented:
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
 
Monroe406Author Commented:
>> 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
 
Monroe406Author Commented:
The following needs to be added to your example to work...

uses
      Sysutils,
      Windows,
..

var
      Mutex: THandle;

...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

  • 5
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now