Solved

Is my application currently running?

Posted on 2004-04-17
11
863 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
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 

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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Delphi XE10, MySQL Query 4 164
How to debug For loops? 3 56
Moving (cutting/pasting) controls in a TTabbedNotebook... 7 42
Graphics32 under Delphi 10.1 Berlin 2 98
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…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…

809 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