Solved

Is my application currently running?

Posted on 2004-04-17
11
861 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
 

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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

867 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now