Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Delphi : Restore application if already running instead of starting new instance

Posted on 2009-02-13
5
Medium Priority
?
2,165 Views
Last Modified: 2013-11-25
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.
0
Comment
Question by:mychel_normandeau
  • 2
  • 2
5 Comments
 
LVL 1

Expert Comment

by:jyh1002
ID: 23636338
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
 
LVL 4

Expert Comment

by:dprochownik
ID: 23640235
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
 

Accepted Solution

by:
mychel_normandeau earned 0 total points
ID: 23685515
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
 
LVL 4

Expert Comment

by:dprochownik
ID: 23685911
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
 

Author Comment

by:mychel_normandeau
ID: 23686427
Yeah I supposed that isIconin = IsIconic when I tested your code :)
0

Featured Post

Get free NFR key for Veeam Availability Suite 9.5

Veeam is happy to provide a free NFR license (1 year, 2 sockets) to all certified IT Pros. The license allows for the non-production use of Veeam Availability Suite v9.5 in your home lab, without any feature limitations. It works for both VMware and Hyper-V environments

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…

579 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question