How Can I Prevent
Multiple Instances of My Application?
Solution 1
From: "David S. Lee" <davidlee@crl.com>
This is the
way I do it:
In the
begin..end block of the .dpr:
begin
if HPrevInst <>0 then begin
ActivatePreviousInstance;
Halt;
end;
end;
Here is the
unit I use:
unit
PrevInst;
interface
uses
WinProcs,
WinTypes,
SysUtils;
type
PHWnd = ^HWnd;
function
EnumApps(Wnd: HWnd; TargetWindow: PHWnd): bool; export;
procedure
ActivatePreviousInstance;
implementation
function
EnumApps(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
ActivatePreviousInstance;
var
PrevInstWnd: HWnd;
begin
PrevInstWnd := 0;
EnumWindows(@EnumApps,LongInt(@PrevInstWnd));
if PrevInstWnd <> 0 then
if IsIconic(PrevInstWnd) then
ShowWindow(PrevInstWnd,SW_Restore)
else
BringWindowToTop(PrevInstWnd);
end;
end.
Solution 2
From: "The Graphical Gnome"
<uddf@gnomehome.demon.nl>
Taken from
Delphi 2 Developers Guide by Pacheco and Teixeira with heavy modifications.
Usage: In
the Project source change to the following
if InitInstance
then
begin
Application.Initialize;
Application.CreateForm(TFrmSelProject,
FrmSelProject);
Application.Run;
end;
unit
multinst;
{
Taken from Delphi 2 Developers Guide by
Pacheco and Teixeira
With heavy Modifications.
Usage:
In the Project source change to the
following
if InitInstance then
begin
Application.Initialize;
Application.CreateForm(TFrmSelProject,
FrmSelProject);
Application.Run;
end;
That's all folks ( I hope ;()
}
interface
uses
Forms, Windows, Dialogs, SysUtils;
const
MI_NO_ERROR = 0;
MI_FAIL_SUBCLASS = 1;
MI_FAIL_CREATE_MUTEX = 2;
{ Query
this function to determine if error occurred in startup. }
{ Value
will be one or more of the MI_* error flags. }
function
GetMIError: Integer;
Function
InitInstance : Boolean;
implementation
const
UniqueAppStr : PChar; {Change for every Application}
var
MessageId: Integer;
WProc: TFNWndProc = Nil;
MutHandle: THandle = 0;
MIError: Integer = 0;
function
GetMIError: Integer;
begin
Result := MIError;
end;
function
NewWndProc(Handle: HWND; Msg: Integer; wParam,
lParam: Longint): Longint;
StdCall;
begin
{ If this is the registered message... }
if Msg = MessageID then begin
{ if main form is minimized, normalize it
}
{ set focus to application }
if IsIconic(Application.Handle) then begin
Application.MainForm.WindowState :=
wsNormal;
ShowWindow(Application.Mainform.Handle,
sw_restore);
end;
SetForegroundWindow(Application.MainForm.Handle);
end
{ Otherwise, pass message on to old window
proc }
else
Result := CallWindowProc(WProc, Handle,
Msg, wParam, lParam);
end;
procedure
SubClassApplication;
begin
{ We subclass Application window procedure
so that }
{ Application.OnMessage remains available
for user. }
WProc :=
TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC,
Longint(@NewWndProc)));
{ Set appropriate error flag if error
condition occurred }
if WProc = Nil then
MIError := MIError or MI_FAIL_SUBCLASS;
end;
procedure
DoFirstInstance;
begin
SubClassApplication;
MutHandle := CreateMutex(Nil, False,
UniqueAppStr);
if MutHandle = 0 then
MIError := MIError or
MI_FAIL_CREATE_MUTEX;
end;
procedure
BroadcastFocusMessage;
{ This
is called when there is already an instance running. }
var
BSMRecipients: DWORD;
begin
{ Don't flash main form }
Application.ShowMainForm := False;
{ Post message and inform other instance to
focus itself }
BSMRecipients := BSM_APPLICATIONS;
BroadCastSystemMessage(BSF_IGNORECURRENTTASK
or BSF_POSTMESSAGE,
@BSMRecipients,
MessageID, 0, 0);
end;
Function
InitInstance : Boolean;
begin
MutHandle := OpenMutex(MUTEX_ALL_ACCESS,
False, UniqueAppStr);
if MutHandle = 0 then
begin
{ Mutex object has not yet been created,
meaning that no previous }
{ instance has been created. }
ShowWindow(Application.Handle,
SW_ShowNormal);
Application.ShowMainForm:=True;
DoFirstInstance;
result := True;
end
else
begin
BroadcastFocusMessage;
result := False;
end;
end;
initialization
begin
UniqueAppStr := Application.Exexname;
MessageID := RegisterWindowMessage(UniqueAppStr);
ShowWindow(Application.Handle, SW_Hide);
Application.ShowMainForm:=FALSE;
end;
finalization
begin
if WProc <> Nil then
{ Restore old window procedure }
SetWindowLong(Application.Handle,
GWL_WNDPROC, LongInt(WProc));
end;
end.
Solution 3
From: "Jerzy
A.Radzimowski" <jerzyara@odn.zgora.pl>
VAR
MutexHandle:THandle;
Var
UniqueKey : string;
FUNCTION
IsNextInstance:BOOLEAN;
BEGIN
Result:=FALSE;
MutexHandle:=0;
MutexHandle:=CREATEMUTEX( NIL,TRUE,
UniqueKey);
IF MutexHandle<>0 THEN
BEGIN
IF GetLastError=ERROR_ALREADY_EXISTS THEN
BEGIN
Result:=TRUE;
CLOSEHANDLE(MutexHandle);
MutexHandle:=0;
END;
END;
END;
begin
CmdShow:=SW_HIDE;
MessageId:=RegisterWindowMessage(zAppName);
Application.Initialize;
IF IsNextInstance
THEN
PostMessage(HWND_BROADCAST,
MessageId,0,0)
ELSE
BEGIN
Application.ShowMainForm:=FALSE;
Application.CreateForm(TMainForm,
MainForm);
MainForm.StartTimer.Enabled:=TRUE;
Application.Run;
END;
IF MutexHandle<>0 THEN
CLOSEHANDLE(MutexHandle);
end.
in MainForm
you need add code for process private message
PROCEDURE
TMainForm.OnAppMessage( VAR M:TMSG; VAR Ret:BOOLEAN );
BEGIN
IF M.Message=MessageId THEN
BEGIN
Ret:=TRUE;
//
BringWindowToTop !!!!!!!!
END;
END;
INITIALIZATION
ShowWindow(Application.Handle, SW_Hide);
END.
inny
Prevent
multi instances of application
Use
FindWindow function to find another window with appropriate class name and
caption. Use this code in project source.
if
FindWindow('TForm1','QQQ')=0 then
begin
Application.Initialize;
Application.CreateForm(TForm1,Form1);
Application.Run;
end;