Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to ensure only one instance of application runs at once?

How To

How to ensure only one instance of application runs at once?

by  roo0047  Posted    (Edited  )
This is the final of several incarnations. I can not take credit for all the code. It once had more comments than code and in an overzealous clean-up, all the credits were removed. I will search my archives and edit later to give credit where it is due.

First the unit, followed by how it is used:
Code:
unit PrevInst;

interface

Uses
  Windows, SysUtils, Messages;

function ActivatePrevInstance(const MainFormClass, ATitle: string): Boolean;

(*
Usage:
  if ActivatePrevInstance(TMainForm.ClassName, '') then
    Exit;
*)

implementation

function StrPAlloc(const S: string): PChar;
begin
  Result := StrPCopy(StrAlloc(Length(S) + 1), S);
end;

function GetWindowParent(Wnd: HWND): HWND;
begin
  Result := GetWindowLong(Wnd, GWL_HWNDPARENT);
end;

function WindowClassName(Wnd: HWND): string;
var Buffer: array [0..255] of Char;
begin
  SetString(Result, Buffer, GetClassName(Wnd, Buffer, SizeOf(Buffer) - 1));
end;

function WindowsEnum(Handle: HWND; Param: Longint): BOOL; export; stdcall;
begin
  if WindowClassName(Handle) = 'TAppBuilder' then
  begin
    Result := False;
    PLongint(Param)^ := 1;
  end
  else
    Result := True;
end;

procedure ActivateWindow(Wnd: HWND);
begin
  if Wnd <> 0 then
  begin
    ShowWindow(Wnd, SW_SHOWNOACTIVATE);   //ShowWinNoAnimate(Wnd, SW_SHOW);
    SetForegroundWindow(Wnd);
  end;
end;

function FindPrevInstance(const MainFormClass, ATitle: string): HWnd;
var
  BufClass, BufTitle: PChar;
begin
  Result := 0;
  if (MainFormClass = '') and (ATitle = '') then Exit;
  BufClass := nil; BufTitle := nil;
  if (MainFormClass <> '') then
    BufClass := StrPAlloc(MainFormClass);
  if (ATitle <> '') then
    BufTitle := StrPAlloc(ATitle);
  try
    Result := FindWindow(BufClass, BufTitle);
  finally
    StrDispose(BufTitle);
    StrDispose(BufClass);
  end;
end; //FindPrevInstance

function ActivatePrevInstance(const MainFormClass, ATitle: string): Boolean;
var
  PrevWnd, PopupWnd, ParentWnd: HWnd;
  IsDelphi: Longint;
begin
  Result := False;
  PrevWnd := FindPrevInstance(MainFormClass, ATitle);
  if PrevWnd <> 0 then begin
    ParentWnd := GetWindowParent(PrevWnd);
    while (ParentWnd <> GetDesktopWindow) and (ParentWnd <> 0) do begin
      PrevWnd := ParentWnd;
      ParentWnd := GetWindowParent(PrevWnd);
    end;
    if WindowClassName(PrevWnd) = 'TApplication' then begin
      IsDelphi := 0;
      EnumThreadWindows(GetWindowTask(PrevWnd), @WindowsEnum, LPARAM(@IsDelphi));
      if Boolean(IsDelphi) then
        Exit;
      if IsIconic(PrevWnd) then  { application is minimized }
      begin
        SendMessage(PrevWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
        Result := True;
        Exit;
      end
      else
        ShowWindow(PrevWnd, SW_SHOWNOACTIVATE); {ShowWinNoAnimate(PrevWnd, SW_SHOWNOACTIVATE);}
    end
    else
      ActivateWindow(PrevWnd);
    PopupWnd := GetLastActivePopup(PrevWnd);
    if (PrevWnd <> PopupWnd) and IsWindowVisible(PopupWnd) and IsWindowEnabled(PopupWnd) then
      SetForegroundWindow(PopupWnd)
    else
      ActivateWindow(PopupWnd);
    Result := True;
  end;
end; //ActivatePrevInstance

end.
The following DPR (project1.exe) will only launch once outside the IDE:

IMPORTANT NOTE: This function works ONLY if the Delphi IDE is NOT running. There is a line of code in ActivatePrevInstance "if Boolean(IsDelphi) then exit;" to allow debugging. It returns "false" if the IDE is running.
Code:
program Project1;

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

{$R *.res}

begin
  if ActivatePrevInstance(TForm1.ClassName, '') then
    Exit;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top