Quelle est la meilleure façon de réactiver une application exécutée dans la barre d’état ?

StackOverflow https://stackoverflow.com/questions/3286136

Question

J'ai une application Delphi qui s'exécute réduite à une icône dans la barre d'état.Lorsque vous double-cliquez sur l'icône de la barre d'état, l'application ouvre un formulaire d'interface utilisateur non modal.

J'ai ajouté une logique à l'application pour détecter si elle est déjà en cours d'exécution.S'il ne fonctionne pas, il démarre et se minimise dans le bac.

S'il est déjà en cours d'exécution, je souhaite qu'il passe le contrôle à la première instance de lui-même et ouvre le formulaire non modal, puis quitte (la deuxième instance).Quelle est la meilleure façon de procéder ?

Tia R

Était-ce utile?

La solution

La méthode Microsoft n'est pas parfaite, donc je préfère la vieille école :

const WM_KNOCK_KNOCK = WM_USER + 42;
{ or WM_USER + 265 or any number you like, consult PSDK documentation why WM_USER range }
{ or do RegisterWindowMessage }

{...}

procedure TMainForm.FormCreate(Sender: TObject);
var
  Window: HWND;
begin 
  Window := FindWindow(PChar({MainForm.}ClassName), nil);
  { 
  i neither remember how it works exactly nor have time to investigate right now, 
  so quick and dirty validity test follows:
  }
  Assert(not (HandleAllocated and (Window = Handle)), 'failed, use fallback');
  {
  if Window <> 0 then
  begin
    PostMessage(Window, WM_KNOCK_KNOCK, 0, 0);
    Halt;
  end;

  { regular initialization }

end;

Désormais, le gestionnaire de messages WM_KNOCK_KNOCK de première instance exécute une routine de réveil.


Je n'ai aucune idée de ce que vous faites exactement lorsque vous recevez WM_LBUTTONUP (ou peut-être WM_LBUTTONDBLCLK) dans votre wrapper Shell_NotifyIcon (Application.Restore, peut-être ?).Comme l'a dit Chris Thornton, il n'existe pas d'état « réduit au bac », c'est artificiel.


Retomber:si l'assertion échoue, notez quel code dépend uniquement de la fonction de classe ClassName donc pourrait être facilement déplacé hors de FormCreate et invoqué avant que l'application ne le crée.

Autres conseils

le Méthode recommandée de détecter un autreL'instance d'une application donnée est destinée à cette application pour créer un fichier mutex nommé ou verrouiller un fichier dans un emplacement bien connu, de sorte que la seconde instance déclenche une erreur lorsque vous essayez de créer le même mutex ou de verrouiller le même fichier.Une fois que vous savez qu'il y a une autre instance en cours d'exécution, vous pouvez trouver la poignée de processus pour cette instance et l'envoyer un message à restaurer s'il est minimisé.

program Only_One_Mutex;

//undefine this   {.$define useMutex} to make it a multi instance app.
{$define useMutex}

uses
  Forms,
  Windows,
  Messages,
  MainForm in 'MainForm.pas' {frmMain};

{$R *.res}

{$ifdef useMutex}
var
  Mutex : THandle;
{$endif}


function pBuffStr( Var S1: String; S:String ): PChar;
begin
  FillChar(S1,SizeOf(S1),#0); {clear out the destination string}
  S1:= S+#0;                  {set it equal the source}
  Result:= @S1[1];            {result is a PChar pointer }
end;

procedure WindowToTop( WN: String );
  var
    iTitle: integer;
    S1,S  : String;
    Done: Boolean;
begin
  Done:= False;
  While NOT Done do begin
    if Pos(';',WN) > 0 then begin
      S:= Copy(WN,1,Pos(';',WN)-1);
      WN:= Copy(WN,Pos(';',WN)+1,Length(WN));
    end else begin
      S:= WN;
      Done:= True;
    end; {if Pos}
    iTitle:= FindWindow( nil, pBuffStr(S1,S) );
    if iTitle <> 0 then
      if NOT SetForegroundWindow( iTitle ) then
        GetLastError();
    Application.ProcessMessages;
  end; {while NOT Done}
end;

procedure RestoreWindow( WN: String );
  var
    iTitle: integer;
    Dest, S  : String;
    Done: Boolean;
begin
  Done:= False;
  While NOT Done do begin
    if Pos(';',WN) > 0 then begin             {is there more than ONE name}
      S:= Copy(WN,1,Pos(';',WN)-1);           {copy the first name of the original}
      WN:= Copy(WN,Pos(';',WN)+1,Length(WN)); {reduce the original string}
    end else begin
      S:= WN;                                 {only one name, so copy it}
      Done:= True;                            {this loop is done}
    end; {if Pos}
    iTitle:= FindWindow( nil, pBuffStr(Dest,S) ); {search for the window name}
    if iTitle <> 0 then                           {if found, then restore it}
      DefWindowProc(iTitle, WM_SYSCOMMAND, SC_RESTORE, SC_RESTORE);
  end; {while NOT Done}
end;


//=================================================================

procedure AppRun;
begin
  Application.Initialize;
  Application.Title := 'Only One Prog';
  Application.CreateForm(TfrmMain, frmMain);
  Application.Run;
end;

begin

{$ifdef useMutex}
  //global var declarations in the mainform.
  {=====================================================================}
  //ATitle MUST match the assigned Application.Title in AppRun
  //and Application.Title can "NOT" be a constant or var.
  ATitle   := 'Only One Prog';

  { THIS IS HOW IT KEEPS THE SECOND INSTANCE FROM STARTING,
    by using a MUTEX, and a MAINFORM window title  }
  //any text appender will work.
  AMutex   := ATitle + ' Mutex Thu, Jul/12/2012';

  //mainform's caption
  ACaption := ATitle + ', Mainform Caption';

  //a label on the mainform
  ALabel   := ATitle + ', MainForm Label-using mutex';
  {=====================================================================}

  Mutex := CreateMutex(nil, True, PAnsiChar( AMutex ));
  if (GetLastError = ERROR_ALREADY_EXISTS) then begin
    try
      RestoreWindow( ACaption );
      WindowToTop( ACaption );       //main form's name
    finally
      CloseHandle(Mutex);
    end;
  end else
    if  (Mutex <> 0)
    AND (GetLastError <> ERROR_ALREADY_EXISTS)
    then begin
     try
       AppRun;
     finally
       CloseHandle(Mutex);
     end;
    end;
{$else}
  //global var declarations in the mainform.
  {=====================================================================}
  ATitle   := 'More than One';                  //global declaration in the mainform.
  //mainform's caption - THIS IS HOW IT KEEPS THE SECOND INSTANCE FROM STARTING
  ACaption := ATitle + ', Mainform Caption';//global declaration in the mainform.
  //a label on the mainform
  ALabel   := ATitle + ', MainForm Label-multi exe';  //global declaration in the mainform.
  {=====================================================================}
  AppRun;
{$endif}

end.


unit MainForm;

interface

uses
  Windows, Messages, SysUtils,
  Variants, Classes, Graphics,
  Controls, Forms,   Dialogs, StdCtrls, LblEffct;


type
  TfrmMain = class(TForm)
    le1: TLabelEffect;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

  //these GLOBAL vars, are assigned values in the program source (.dpr) file.
  ATitle,
  ACaption,
  ALabel,
  AMutex  :String;

implementation

{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Caption     := ACaption;     //used to ID this form...
  le1.Caption := ALabel;
end;

end.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top