Controlling Application Startup in Delphi 3 by Evan Simpson - esimpson@eramp.net For many programs, having more than one instance running at the same time isn't a problem.  It may even be a desirable feature, in SDI applications like Notepad, for instance. Often, though, the program will read and write data files (or registry keys) in a way which will cause corruption if another copy is launched, or it may simply not make any sense to have multiple instances running. In these cases it is valuable to have a simple mechanism to detect and control instance launches, especially with Windows 98 and its single-click launch interface. Under 16 bit Windows, the solution was simple; Just examine the previous instance global variable to see if a copy is already running, and do the right thing. Under Win32, things are a bit more complicated. Several solutions are available on the Web, including one on the Borland Tips page, but I still felt compelled to write my own for several reasons. First, I needed to transmit the command line parameters of a second launch attempt to the primary instance in one program I wrote (it processes BMP files dragged onto its Explorer icon).  Second, I wanted a plug-in unit which required minimal alteration from one program to the next, and little or no foolery in my DPR file.  Third, I wanted it to be secure, reliable, and fast; In particular, it should run before any other VCL code initializes or allocates anything. To meet the first requirement, I used WM_COPYDATA on the command line string. This in turn required me to get a window handle from the primary instance to use as a target for the message.  FindWindow handles this nicely, but I couldn't use the automatic application window or any other standard window of the application, because of the third requirement. The second requirement led me to place all of the code into a unit which is simply placed in the DPR "uses" clause. The actual instance management code runs in the unit's initialization.  Global variables in the interface part provide the event hook and passed data storage. Due to the third requirement, the unit must be the very first unit used by the DPR, and could not use any other application unit. In particular, almost every unit is likely to use Forms, and Forms is normally the first unit used by a DPR, but Forms sets up and initializes the whole Application framework. The result of all this is the InstanceManager unit below. Simply make it the first unit in your program's DPR's uses list, and edit the constant declarations to fit your needs. Note that by using the same string constant for two or more different programs, you can create a "family" of executables which share instance management - I use this ability in a timeclock program, which not only should not run more than once, but cannot run at the same time as its administative utility.  Also, this unit doesn't just prevent a second instance from running. It can call a notification event, which can decide on a case-by-case basis whether to allow the other instance to run, perhaps by examining the command line. unit InstanceManager; interface {Notes: make InstanceManager the *very first* unit in your program's USES clause.  To take advantage of the notification and launch-string, put a method with no parameters in one of your forms and assign it to triggerProc. Once triggerProc is called, rcvStr contains the command line of the launch attempt. If the only reaction you want is to bring the first instance to the front, just put a method like the following in your main form, and in the form's OnCreate set InstanceManager.triggerProc:=ToFront;     procedure TForm1.ToFront;     begin       Application.Restore;       Application.BringToFront;     end; If you don't have a dependable main form, make ToFront a class procedure of any old class.} { Customize these constants before using } const UniqueAppName = 'Unique application name';       AppNotifyValue: integer = 0; var rcvStr: string;     rcvValue: integer;     ForbidOtherInstance: boolean = True;     triggerProc: procedure of object; implementation uses Windows, SysUtils, Messages; var mutex, thisWnd: HWND;     IMWndClass: TWndClassA;     mustHalt: boolean;     copydata: TCOPYDATASTRUCT; function IMWndProc(HWindow: HWnd; Message, WParam: Longint; LParam: Longint): Longint; stdcall; begin   if Message=WM_COPYDATA then     begin       rcvStr := StrPas(PCOPYDATASTRUCT(lParam).lpData);       rcvValue := PCOPYDATASTRUCT(lParam).dwData;       if Assigned(triggerProc) then triggerProc;       Result := Ord(ForbidOtherInstance);     end   else     Result := DefWindowProc(hWindow, Message, WParam, LParam); end; initialization   FillChar(IMWndClass, SizeOf(IMWndClass), 0);   IMWndClass.lpfnWndProc := @IMWndProc;   IMWndClass.hInstance := HINSTANCE;   IMwndClass.lpszClassName := 'TInstanceManager';   if Windows.RegisterClass(IMWndClass) = 0 then RaiseLastWin32Error;   mutex := CreateMutex(nil, True, UniqueAppName);   if GetLastError = ERROR_ALREADY_EXISTS then     begin       mustHalt := True;       if WaitForSingleObject(mutex, 5000)=WAIT_OBJECT_0 then         begin           thisWnd := FindWindow(IMwndClass.lpszClassName, UniqueAppName);           if thisWnd = 0 then RaiseLastWin32Error;           CopyData.dwData := AppNotifyValue;           CopyData.lpData := CmdLine;           CopyData.cbData := StrLen(CmdLine);           mustHalt := (SendMessage(thisWnd,WM_COPYDATA,0,Integer(@CopyData))>0);         end;       thisWnd := 0;       ReleaseMutex(mutex);       if mustHalt then Halt;     end   else     begin       thisWnd := CreateWindow(IMwndClass.lpszClassName,UniqueAppName,0,0,0,0,0,0,0,hInstance, nil);       if thisWnd = 0 then RaiseLastWin32Error;       ReleaseMutex(mutex);     end; finalization   if thisWnd>0 then DestroyWindow(thisWnd); end.