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.
mychel_normandeauAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jyh1002Commented:
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/
0
dprochownikCommented:
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;
0
mychel_normandeauAuthor Commented:
jyh1002: LMD tools didn't helped... It even crashed my app when the main form closed (OS leven exception).

dprochownik: Same problem... Still no restore/focus the previous instance...

Solved my problem by using:
http://www.swissdelphicenter.ch/torry/showcode.php?id=1969

with the following code snippet added to AlreadyRunning function.
{add code snippet in the "if Result then" block}
        if restorePreviousInstance then {restorePreviousInstance added to the params list of the function}
        begin
            mainFormPreviousInstance := FindFirstInstanceMainform(aMainformClass.ClassName);
            if IsIconic(mainFormPreviousInstance) then
                ShowWindow(mainFormPreviousInstance, SW_RESTORE);
 
            SetForegroundWindow(mainFormPreviousInstance);
        end;

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
dprochownikCommented:
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

0
mychel_normandeauAuthor Commented:
Yeah I supposed that isIconin = IsIconic when I tested your code :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.