Prevent Multiple Instances of Delphi Application Running

This code will prevent multiple instances of your application from opening, and pass parameter details to the existing application process.

By Tim Trott | Legacy Code | August 16, 2004

Sometimes you may only want a single instance of your application to run at any given time. This code will prevent multiple instances from opening, and pass parameter details (such as file open command) to the existing application.

To go into main (Form1) unit

pascal
var WM_FINDINSTANCE: Integer;

{The basic code contained in the next three procedures,
 which works with the DPR code to allow file association
 and open double-clicked file in the running instance of the app
 was written by Andrius Adamonis}

procedure TForm1.WMRestoreApp(var Msg: TMessage);
begin
  if IsIconic(Application.Handle) then
    Application.RESTORE
  else
    Application.BringToFront;
end;

procedure TForm1.DefaultHandler(var message);
var
  s: String;
begin
  with TMessage(message) do
    if (Msg = WM_FINDINSTANCE) then
    begin
      Result := MyUniqueConst;
    end
    else
    if Msg = WM_OPENEDITOR then
    begin
      SetLength(S, MAX_PATH);
      GlobalGetAtomName(WPARAM, PChar(S), MAX_PATH);
      ShowMessage(S);
      try
        OpenDocument(S);

        except on E: Exception do
            raise Exception.Create('Error opening ' + S + ' - ' + E.message);
      end;
    end
    else
      inherited DefaultHandler(message);
end;
This code goes at the very end of the main unit

initialization {Used in the file association and running instance code}
  WM_FINDINSTANCE := RegisterWindowMessage('Your Custom Handle Message Here');

  if WM_FINDINSTANCE = 0 then
    raise Exception.Create('Initialization failed');

end.

This code goes in the .dpr

pascal
program Sample;

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

{$R *.RES}

var Previous: HWND;
    ATOM: TAtom;

function EnumWindowsCallback(Handle: HWND; Param: LPARAM): Boolean; stdcall;
  function IsMyClass: Boolean;
  var
    ClassName    : array[0..30] of Char;
  begin
    GetClassName(Handle, ClassName, 30);
    [i]/If you change the name of Form1 don't forget to change the string below![/i]
    Result := (StrIComp(ClassName, 'TForm1') = 0) and (SendMessage(Handle, WM_FINDINSTANCE, 0, 0) = MyUniqueConst);
  end;
begin
  Result := not IsMyClass; [i]{ needs True to continue }[/i]
  if not Result [i]{ = MyClass }[/i] then Previous := Handle;
end;

begin
  Previous := 0;
  EnumWindows(@EnumWindowsCallback, 0);

  if Previous <> 0 then
  begin
    PostMessage(Previous, WM_RESTOREAPP, 0, 0);
    if (ParamCount > 0) then
    begin
      ATOM := GlobalAddAtom(PChar(ParamStr(1)));
      SendMessage(Previous, WM_OPENEDITOR, ATOM, 0);
      GlobalDeleteAtom(ATOM);
    end;
    Exit;
  end;

  Application.Initialize;
  Application.Title := 'Sample 1';
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 1 comment(s). Why not join the discussion!

We respect your privacy, and will not make your email public. Learn how your comment data is processed.

  1. AM

    On Monday 18th of November 2019, Amtrit said

    and is it compatible with latest delphi 10.3.2 rio and platform fmx ?