Question:
How can I guarantee that only one instance of my program
executes? Is it possible to restore the previous instance
and shut down if I start more than one instance?
Answer:
Under Win16, you can check the value of hPrevInst at startup. If
it is non-zero, then another instance of your application is
running, and you can take steps to abort the current instance.
Under Win32, hPrevInst is always zero and cannot be relied upon.
You should attempt to create a uniquely named mutex. If the
creation fails, then there is another instance running.
The following example attempts to create a named mutex. If the
mutex fails, a unique system wide custom windows message is
registered with the system, and is then broadcast to all top
level windows. The second instance then shuts down. The
previous instance has also registered this unique custom
system wide message, and has trapped the window procedure of
Form1 to respond to this message. If the message is received,
then Form1 is restored (if minimized) and then made to be
the top level window. Care is taken in the example to
minimize the effect of Delphi/Borland C++ Builder's hidden
application window, and its effect on the task bar icon for Form1.
Example:
{The code for OneInstance.dpr}
program OneInstance;
uses
Windows,
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
begin
{Attempt to create a named mutex}
CreateMutex(nil, false, 'MyApp');
{if it failed then there is another instance}
if GetLastError = ERROR_ALREADY_EXISTS then begin
{Send all windows our custom message - only our other}
{instance will recognise it, and restore itself}
SendMessage(HWND_BROADCAST,
RegisterWindowMessage('MyApp'),
0,
0);
{Lets quit}
Halt(0);
end;
Application.Initialize;
{Tell Delphi to un-hide it's hidden application window}
{This allows our instance to have a icon on the task bar}
Application.ShowMainForm := true;
ShowWindow(Application.Handle, SW_RESTORE);
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
{The code for unit1.pas}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
var
OldWindowProc : Pointer; {Variable for the old windows proc}
MyMsg : DWord; {custom systemwide message}
function NewWindowProc(WindowHandle : hWnd;
TheMessage : LongInt;
ParamW : LongInt;
ParamL : LongInt) : LongInt stdcall;
begin
if TheMessage = MyMsg then begin
{Tell the application to restore, let it restore the form}
SendMessage(Application.handle, WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(Application.Handle);
{We handled the message - we are done}
Result := 0;
exit;
end;
{Call the original winproc}
Result := CallWindowProc(OldWindowProc,
WindowHandle,
TheMessage,
ParamW,
ParamL);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
{Register a custom windows message}
MyMsg := RegisterWindowMessage('MyApp');
{Set form1's windows proc to ours and remember the old window proc}
OldWindowProc := Pointer(SetWindowLong(Form1.Handle,
GWL_WNDPROC,
LongInt(@NewWindowProc)));
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{Set form1's window proc back to it's original procedure}
SetWindowLong(Form1.Handle,
GWL_WNDPROC,
LongInt(OldWindowProc));
end;
begin
{Tell Delphi to hide it's hidden application window for now to avoid}
{a "flash" on the taskbar if we halt due to another instance}
ShowWindow(Application.Handle, SW_HIDE);
end.