1. Home
  2. Computing & Technology
  3. Delphi Programming
Controlling the number of application instances
Page 2: Handling previous instances of an application
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Page 1: Where it all starts...
• Page 3: Limiting multiple instances. Restoring last instance.
• Page 4: Full CODE
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Delphi Project File (DPR)
• Windows API and Delphi

Once you know where to place the code to control the number of running instances of your application, we can proceed with a discussion on the various "Am I running" code checks. Along the process we'll also discuss several Windows API programming techniques.

What follows is an overview of techniques one could describe as: "I could use this one", and "but I need more power" or "this is too complicated"... In general, all the techniques discussed below can do the job - however, the code I'm using (and the reason you are reading this article) will be presented last. If you can't wait, or if you are interested in nothing but the best approach, you can skip this page and go for the final solution - the ultimate "I can be instanced only a limited number of times (one ore more)" Delphi solution.

There can be only one (instance of an application)!
As introduced on the previous page, first you need to write some code that can query the system (Windows) for the existence of a running instance of the application. If there is an instance of the application already running, you'll need to make sure the program is not executed for the second time, and the previous instance gets to be the active program.

FindWindow - not good enough
The easiest way to look for an already running instance of an application is to use the FindWindow API function. The FindWindow function retrieves the handle of the window provided with the class name and window caption. In Delphi, the name of the window (form) class is the name of the form's class, for example 'TForm1'. Here's the code:

program Project1;

uses
  Forms, Windows,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}
var
  PreviousHandle : THandle;
begin
  PreviousHandle := FindWindow('TForm1','Form1'); 
  if PreviousHandle = 0 then
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end
  else
    SetForegroundWindow(PreviousHandle);
end.

In our sample application we have only one form: Form1. This form is the main form of the project. To find a copy of the application already running, we can call the FindWindow API function that retrieves the handle of an existing window (the main form of the application). If the function fails (window with a specified class name and caption canot be found) the function returns 0. If the function returns the non-zero handle value, meaning that the system has found a window with specified parameters, we use the SetForegroundWindow API call. This function, provided with the window handle, activates the window and brings it to the foreground - making it the active window. Since Form1 is the main window of the application - the (already running) application becomes active. However, if the window was minimized we'll first need to restore it to its previous state and then bring it to "top".

The code above might look ok, but is not what we want.
First, such a code would prevent you from running your application from the IDE (at design time) - since at design time the window with the specified class name and the caption already exists, it's the design time window of your main form.
Second, this code is not so safe, since there may be many Delphi applications on the system running, that have a form whose class name is "TForm1" - how can you be sure that this particular form (window) found by the FindWindow function is in fact a form belonging to your application? You cannot.

To overcome this problem, we'll turn to threading. In Windows, one common way of object synhronization is creating a mutex object (mutually exclusive). In general, mutexes are used to synchronize two (or more) different applications - in our case we'll create a mutex to synchronize instances of the same application.

Mutex - could do
The following code attempts to create a named mutex. If the function (CreateMutex) fails, you can be sure that an instance of the application is already running.

program Project1;

uses
  Forms, Windows,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}
var
  Mutex : THandle;
begin
  Mutex := CreateMutex(nil, True, 'My_Unique_Application_Mutex_Name'); 
  if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then
  begin

    // code to searh for, and activate 
    // the previous (first) instance

  end
  else
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
    if Mutex <> 0 then
      CloseHandle(Mutex); 
    end;
  end;
end.

As you can "read" from the above code, if the mutex object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS. If this is the case, your task is to write the code that will look for the previous instance and make it active.

Note: the CreateMutex function requires the name of the mutex object as the last parameter. In the above example, the name provided was 'My_Unique_Application_Mutex_Name'. What this means, is that for every application you want to be executed only once, you'll need to assign a different mutex name - and this could lead you into problems. In this stage of the program execution (or better to say startup), you cannot use the application full path (ParamStr(0)) or the Application.Title property, since the Application object is not yet fully accessible.

Activating the previous instance
As you can see from the previous examples, it is rather easy to check for an existing instance of a running application. However, if you want to make a user-friendly experience with a "can-be-run-only-once" type of application, you'll need to make sure that the previous instance gets enabled and visible, by bringing it to the foreground - even if it was minimized. In either of the previous cases you'll need to find the main window of the application - any notify it that it needs to "restore".

Searching for a previous instance
One way to go is to loop through all the top-level windows and look for a specific window - the previous instance of the application. This approach includes using Windows callback functions, like EnumWindows. Once a main window from the previous instance was found we send it a custom message, the running instance catches the message and restores itself. The second instance needs to shut down.

As discussed in the "Hey Windows, call me!" article, EnumWindows function enumerates all top-level windows by passing the handle of each window to a custom defined callback function. The task of this function is to find wheter the received handle equals the handle of the main window (form) of the running instance. If it does, the main form of the already running instance is found, the enumeration can be stopped, and the message can be send to the application. The application than needs to know how to handle the message received.

This technique requires that you add code to the OnMessage event of the global Delphi application object (you'll probably place the code in the source of the main form), or to create a procedure that responds only to your custom message. The downside of this approach is that you need to alter the source code of the main form, too.

Another downside is that the enumeration function needs to know the class name of the main form of your application, since it needs to compare it to every handle received by Windows (as a result of windows enumeration). What's bad here is that you need to call the function before the main form is created and the Form1.Handle can be queried.

In order to compare each window (using its hande) with the main window of your (already running) application, you'll need to match them using their class names. And to get the class name from a handle is, well, not so trivial. What is left for you to do, is to "fight" against Windows (the EnumWindows function, that is) with only the HInstance variable (handle to "this" instance of the application). This is not all: if your application's main form class name matches the class name (of the window) that is being processed, you need to make sure that this form belongs to exactly the same application you are trying to run (trying to execute once more). What this means is that you can have two or more applications with the main form's class name 'TMainForm' (or even worse: 'TForm1'). Either way, below is the code that you can use.

Note: I'll only list here the enumeration (callback) function. You call the function after you have found a previous instance, like:

EnumWindows(@LookForPreviousInstance, 0);

function LookForPreviousInstance
  (Handle : THandle; Param : Cardinal): boolean; stdcall;
var
 buf : array[0..255] of char;
 WindowModuleName : string;
 WindowClassName : string;
 wih : THandle; // window instance handle
begin
 Result := True;
 
 GetClassName(Handle, buf, SizeOf(buf));
 WindowClassName := buf;
 
 //form class name match!
 if WindowClassName = TForm1.ClassName then
 begin
   wih := GetWindowLong(Handle, GWL_HINSTANCE),
    
   GetModuleFileName(wih, buf, SizeOf(buf));
   WindowModuleName := buf;
   
   //from the "same" application?
   if WindowModuleName = ThisModuleName then
   begin
     FoundIt := True;
     FoundHandle := Handle;
     //stop the enumeration
     Result := False;
   end;
 end;
end;

Note: ThisModuleName is the name of the module file name you can find for "this" instance using the GetModuleFileName(Hinstance, buf, SizeOf(buf))... call, before you call the EnumWindows procedure.

Note 2: look at the line in red, you compare the processed window class name to your main form's class name. What if you decide to change the main form of your application from TForm1 to TMainForm? You'll need to alter this code too!

Now, when the enumeration is finished, and the previous instance is found (FoundIt := True), you can send a message to the running instance using the found handle ("FoundHandle") ... I'm not going to post the code here, since we are *not* interested in this approach.

RegisterWindowMessage
Another way to go is to register a system wide custom windows message, and to broadcast it to all top level windows. In other words, your application first registers a unique message, then if the application is already running, the message is broadcasted (send to all windows) and the second copy than shuts down. Since the first instance of the application has already registered the same message, you need to make sure that it can react on that particular message and respond to it (by restoring itself). The code can again be placed in the source of the main form.

Below, you'll find an example. The first listing is the project file source, the second is the source of the main form's unit.

program Project1;

uses
  Forms, Windows, Messages,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}
var
  Mutex : THandle;
begin
  MyMsg := RegisterWindowMessage('My_Unique_App_Message_Name');
  Mutex := CreateMutex(nil, True, 'My_Unique_Application_Mutex_Name'); 
  if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then
  begin
    SendMessage(HWND_BROADCAST, MyMsg, 0, 0);
  end
  else
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
    if Mutex <> 0 then
      CloseHandle(Mutex); 
    end;
  end;
end.

The RegisterWindowMessage function defines a new window message that is guaranteed to be unique throughout the system. If two applications use the same message string, the same id will be generated. The returned message value can then be used with the SendMessage function.

The source of the main form, where you handle the message:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  MyMsg: Cardinal;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
   Application.OnMessage := AppMessage;
end;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
   if Msg.Message = MyMsg then
   begin
      Application.Restore;
      SetForeGroundWindow(Application.MainForm.Handle);
      Handled := true;
   end;
end;

end.

What the above code ensures, in the AppMessage function, is that the first instance of the application knows how to react on that specific message registered using the RegisterWindowMessage call. When the message is received, the Application.Restore method is called (to restore the application to its previous size if it was minimized), and the main window of the application is placed on the foreground.

The ultimate solution!
Uh, oh, how many Windows API this, and Windows API that calls ;)
Where are we now? We have the code you can use to run-once enable your application, it's a mess but it should work!

Suppose you don't want to change the source of the main form every time you need to "run-once" enable your application. Why not have all the code in a separate unit that you can easily add to your project's uses list, and call only one function (Restore-If-Running) that does all the work. Even more, presume a situation when you want your application to be executed (instanced) only a limited number of times (not once, as described here, but only twice, for example)! How about that?

It's time for you to take a look at the next page where the ultimate "I can be instanced only a limited number of times (one ore more)" Delphi solution is revealed...

Next page > Limiting multiple instances. Restoring last instance. > Page 1, 2, 3, 4

Explore Delphi Programming
About.com Special Features

Holiday Central

What to eat, where to go, fun things to do and how to save money on the perfect gifts. More >

Family Tech Center

Stay connected and entertained with reviews on tips on the latest HDTVs, cellphones and more. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming

©2009 About.com, a part of The New York Times Company.

All rights reserved.