Q:  How can I write my Delphi program to detect if there is already another copy running and exit if so?

A:  Here is some code from Pat Ritchey that works great.  Create a unit called PrevInst and add it to your uses clause.  Here's the code:

 unit PrevInst;

 interface

 uses
  WinTypes, WinProcs, SysUtils;

 type
  PHWND = ^HWND;
  function EnumFunc(Wnd:HWND; TargetWindow:PHWND): bool; export;
  procedure GotoPreviousInstance;

 implementation

  function EnumFunc(Wnd:HWND; TargetWindow:PHWND): bool;
  var
    ClassName : array[0..30] of char;
  begin
    Result := true;
    if GetWindowWord(Wnd,GWW_HINSTANCE) = hPrevInst then
       begin
       GetClassName(Wnd,ClassName,30);
       if StrIComp(ClassName,'TApplication') = 0 then
          begin
          TargetWindow^ := Wnd;
          Result := false;
          end;
       end;
  end;

  procedure GotoPreviousInstance;
  var
    PrevInstWnd : HWND;
  begin
    PrevInstWnd := 0;
    EnumWindows(@EnumFunc,longint(@PrevInstWnd));
    if PrevInstWnd <> 0 then
       if IsIconic(PrevInstWnd) then
          ShowWindow(PrevInstWnd,SW_RESTORE)
       else
          BringWindowToTop(PrevInstWnd);
  end;

  end.

  And then make the main block of your *.DPR file look something like this--

 if hPrevInst <> 0 then
    GotoPreviousInstance
  else
  begin
      Application.CreateForm(MyForm, MyForm);
      Application.Run;
  end;
 

Here is a 32 bit version that I found on compuserve:

unit prevcode;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  function DoIExist(WndTitle : String) : Boolean;
var
  Form1: TForm1;

implementation

{$R *.DFM}

{
 This is a different twist on finding a previous instance of an application in a 32-bit environment. It uses a semaphore (although you could also use a mutex object) instead of performing an EnumWindows to find a previous instance, like you would have done in a 16-bit environment. This is more in line with multi-threaded app design.
}
function DoIExist(WndTitle : String) : Boolean;
var
  hSem    : THandle;
  hWndMe,
  hWndPrev : HWnd;
  semNm,
  wTtl    : Array[0..256] of Char;
begin

  Result := False;

  //Initialize arrays
  StrPCopy(semNm, 'SemaphoreName');
  StrPCopy(wTtl, WndTitle);

  //Create a Semaphore in memory - If this is the first instance, then
  //it should be 0.
  hSem := CreateSemaphore(nil, 0, 1, semNm);

  //Now, check to see if the semaphore exists
  if ((hSem <> 0) AND (GetLastError() = ERROR_ALREADY_EXISTS)) then begin
    CloseHandle(hSem);

    //We'll first get the currently executing window's handle then change its title
    //so we can look for the other instance
    hWndMe := FindWindow(nil, wTtl);
    SetWindowText(hWndMe, 'zzzzzzz');

    //What we want to do now is search for the other instance of this window
    //then bring it to the top of the Z-order stack.
    hWndMe := FindWindow(nil, wTtl);
    if (hWndMe <> 0) then begin
      if IsIconic(hWndMe) then
        ShowWindow(hWndMe, SW_SHOWNORMAL)
      else
        SetForegroundWindow(hWndMe);
    end;

    Result := True;

    //Could put the Halt here, instead of in the FormCreate method,
    //unless you want to do some extra processing.

    //Halt;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  if DoIExist(Self.Caption) then
    Halt;
end;

end.