mychel_normandeau
asked on
Delphi : Restore application if already running instead of starting new instance
I use the following code to limit the number of instances of my application:
http://delphi.about.com/library/code/ncaa100703a.htm
All is working except that if the application if already running the previous instance if not restaured (if minimized) or not focused.
the following lines don't do their job:
if IsIconic(InstanceInfo^.Pre viousHandl e) then
ShowWindow(InstanceInfo^.P reviousHan dle, SW_RESTORE);
SetForegroundWindow(Instan ceInfo^.Pr eviousHand le);
IsIconic returns false even if the previous instance is minimized and SetForegroundWindow is not working at all...
What's wrong?
Thanks!
I use Delphi 2009 under Windows XP.
http://delphi.about.com/library/code/ncaa100703a.htm
All is working except that if the application if already running the previous instance if not restaured (if minimized) or not focused.
the following lines don't do their job:
if IsIconic(InstanceInfo^.Pre
ShowWindow(InstanceInfo^.P
SetForegroundWindow(Instan
IsIconic returns false even if the previous instance is minimized and SetForegroundWindow is not working at all...
What's wrong?
Thanks!
I use Delphi 2009 under Windows XP.
Some time ago I wrote similar application. Below is some code of mine.
If you will run this app first time it will just launch. If you will run it second time it will send windows message to previous instance and close itself.
Because I was running my apps with some string parameter, I'm sending this parameter to previous instance of my program too.
Main application dpr file:
program MyApplication;
uses
Forms,
Windows,
Messages,
SysUtils
ufrmMain in 'ufrmMain.pas' {frmMain},
....;
{$R *.res}
var
gMutex: THandle;
gString: String;
gCopyDataStruct : TCopyDataStruct;
gi: Integer;
vReceiver: THandle;
begin
//Prevent before multi instances
WM_MY_SYNCHRONIZE := RegisterWindowMessage('Som e unique windows message name');
gMutex := CreateMutex(nil, True, 'Unique App Identifier');
if (gMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
gString := '';
gi := ParamCount;
for gi := gi downto 1 do
gString := gString + ' "' + ParamStr(gi)+'"';
//Searching for main form of previous application instance
vReceiver := FindWindow(PChar('TfrmMain '),nil); //TfrmMain is a name of application main form
if vReceiver<>0 then
begin
//Sending message to synchronize data
gCopyDataStruct.dwData := WM_MY_SYNCHRONIZE;
gCopyDataStruct.cbData := 1 + (Length(gString) * SizeOf(Char)) ;
gCopyDataStruct.lpData := PChar(gString) ;
SendMessage(vReceiver, WM_COPYDATA, Application.Handle, Integer(@gCopyDataStruct)) ;
end;
end
else
try
Application.Initialize;
Application.MainFormOnTask bar := True;
Application.CreateForm(Tfr mMain, frmMain);
Application.CreateForm( ... );
....
Application.Run;
finally
if gMutex <> 0 then CloseHandle(gMutex);
end;
end.
My main form unit
unit ufrmMain;
interface
uses ... ;
TfrmMain= class(TForm)
...
private
...
procedure SynchronizeMessage(var Msg : TWMCopyData) ; message WM_COPYDATA;
end;
var
frmMain: TfrmMain;
WM_MY_SYNCHRONIZE: LongWord;
procedure TfrmMain.SynchronizeMessag e(var Msg: TWMCopyData);
var
vParams : string;
begin
if Msg.CopyDataStruct.dwData= SYNCHRONIZ E then
begin
vParams := PChar(Msg.CopyDataStruct.l pData) ;
And here you can restore this instance of application
for example:
if isIconin(Application.Handl e) then
begin
Application.MainForm.Windo wState := wsNormal;
ShowWindow(Application.Mai nform.Hand le, sw_restore);
hCurWnd := GetForegroundWindow;
AttachThreadInput(
GetWindowThreadProcessId(h CurWnd, nil),
GetCurrentThreadId, True);
SetForegroundWindow( Application.MainForm.Handl e); //there should be a handle to window, which should be show on top (currently active windows of yours app).
AttachThreadInput(
GetWindowThreadProcessId(h CurWnd, nil),
GetCurrentThreadId, False);
end;
end;
end;
If you will run this app first time it will just launch. If you will run it second time it will send windows message to previous instance and close itself.
Because I was running my apps with some string parameter, I'm sending this parameter to previous instance of my program too.
Main application dpr file:
program MyApplication;
uses
Forms,
Windows,
Messages,
SysUtils
ufrmMain in 'ufrmMain.pas' {frmMain},
....;
{$R *.res}
var
gMutex: THandle;
gString: String;
gCopyDataStruct : TCopyDataStruct;
gi: Integer;
vReceiver: THandle;
begin
//Prevent before multi instances
WM_MY_SYNCHRONIZE := RegisterWindowMessage('Som
gMutex := CreateMutex(nil, True, 'Unique App Identifier');
if (gMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
gString := '';
gi := ParamCount;
for gi := gi downto 1 do
gString := gString + ' "' + ParamStr(gi)+'"';
//Searching for main form of previous application instance
vReceiver := FindWindow(PChar('TfrmMain
if vReceiver<>0 then
begin
//Sending message to synchronize data
gCopyDataStruct.dwData := WM_MY_SYNCHRONIZE;
gCopyDataStruct.cbData := 1 + (Length(gString) * SizeOf(Char)) ;
gCopyDataStruct.lpData := PChar(gString) ;
SendMessage(vReceiver, WM_COPYDATA, Application.Handle, Integer(@gCopyDataStruct))
end;
end
else
try
Application.Initialize;
Application.MainFormOnTask
Application.CreateForm(Tfr
Application.CreateForm( ... );
....
Application.Run;
finally
if gMutex <> 0 then CloseHandle(gMutex);
end;
end.
My main form unit
unit ufrmMain;
interface
uses ... ;
TfrmMain= class(TForm)
...
private
...
procedure SynchronizeMessage(var Msg : TWMCopyData) ; message WM_COPYDATA;
end;
var
frmMain: TfrmMain;
WM_MY_SYNCHRONIZE: LongWord;
procedure TfrmMain.SynchronizeMessag
var
vParams : string;
begin
if Msg.CopyDataStruct.dwData=
begin
vParams := PChar(Msg.CopyDataStruct.l
And here you can restore this instance of application
for example:
if isIconin(Application.Handl
begin
Application.MainForm.Windo
ShowWindow(Application.Mai
hCurWnd := GetForegroundWindow;
AttachThreadInput(
GetWindowThreadProcessId(h
GetCurrentThreadId, True);
SetForegroundWindow( Application.MainForm.Handl
AttachThreadInput(
GetWindowThreadProcessId(h
GetCurrentThreadId, False);
end;
end;
end;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hmmmm
I suppose that if you would delete line:
if isIconin(Application.Handl e) then
from my code then it should work fine, my mistake.
PS: From time to time, if you are doing such things, windows which are showing, are not on the top of all others windows on the desktop. This happens only sometimes and in most cases can't be propagate so I advice you using below code in OnFormShow event which prevents such behaviour.
I suppose that if you would delete line:
if isIconin(Application.Handl
from my code then it should work fine, my mistake.
PS: From time to time, if you are doing such things, windows which are showing, are not on the top of all others windows on the desktop. This happens only sometimes and in most cases can't be propagate so I advice you using below code in OnFormShow event which prevents such behaviour.
hCurWnd := GetForegroundWindow;
AttachThreadInput(
GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, True);
SetForegroundWindow(Handle); //Current window handle
AttachThreadInput(
GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, False);
ASKER
Yeah I supposed that isIconin = IsIconic when I tested your code :)
All you need to do is just putting component on the main form,
They released LMD-Tools SE 9.04 (LMD 2009)
http://lmdtools.com/download/