Link to home
Start Free TrialLog in
Avatar of mychel_normandeau
mychel_normandeauFlag for Canada

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^.PreviousHandle) then
    ShowWindow(InstanceInfo^.PreviousHandle, SW_RESTORE);
SetForegroundWindow(InstanceInfo^.PreviousHandle);

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.
Avatar of jyh1002
jyh1002

You might like TLMDOneInstance component, which is free.
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/
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('Some 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.MainFormOnTaskbar := True;
      Application.CreateForm(TfrmMain, 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.SynchronizeMessage(var Msg: TWMCopyData);
var
  vParams : string;
begin
  if Msg.CopyDataStruct.dwData=SYNCHRONIZE then
  begin
    vParams := PChar(Msg.CopyDataStruct.lpData) ;

    And here you can restore this instance of application
    for example:

   
if isIconin(Application.Handle) then
    begin
      Application.MainForm.WindowState := wsNormal;
      ShowWindow(Application.Mainform.Handle, sw_restore);

      hCurWnd := GetForegroundWindow;
      AttachThreadInput(
        GetWindowThreadProcessId(hCurWnd, nil),
        GetCurrentThreadId, True);
      SetForegroundWindow( Application.MainForm.Handle); //there should be a handle to window, which should be show on top (currently active windows of yours app).
      AttachThreadInput(
        GetWindowThreadProcessId(hCurWnd, nil),
        GetCurrentThreadId, False);
    end;
 
 end;
end;
ASKER CERTIFIED SOLUTION
Avatar of mychel_normandeau
mychel_normandeau
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hmmmm
I suppose that if you would delete line:
if isIconin(Application.Handle) 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.


  hCurWnd := GetForegroundWindow;
  AttachThreadInput(
                    GetWindowThreadProcessId(hCurWnd, nil),
                    GetCurrentThreadId, True);
  SetForegroundWindow(Handle); //Current window handle
  AttachThreadInput(
                    GetWindowThreadProcessId(hCurWnd, nil),
                    GetCurrentThreadId, False);

Open in new window

Avatar of mychel_normandeau

ASKER

Yeah I supposed that isIconin = IsIconic when I tested your code :)