Каков наилучший способ активировать приложение, запущенное в трее? - PullRequest
1 голос
/ 20 июля 2010

У меня есть приложение delphi, которое минимизируется до иконки в трее.Если дважды щелкнуть значок на панели задач, приложение открывает немодальную форму пользовательского интерфейса.

Я добавил логику в приложение, чтобы определить, запущено ли оно.Если он не работает, он запускается и минимизирует себя в трее.

Если он уже запущен, я хочу, чтобы он передал управление самому первому экземпляру, открыл немодальную форму и затем завершил работу (второй экземпляр).Какой лучший способ сделать это?

TIA R

Ответы [ 3 ]

5 голосов
/ 20 июля 2010

рекомендуемый метод обнаружения другого экземпляра данного приложения - для этого приложения создать именованный мьютекс или заблокировать файл в хорошо известном месте, чтобы второй экземпляр вызывал ошибку, когда вы попробуйте создать тот же мьютекс или заблокировать тот же файл. Как только вы узнаете, что запущен другой экземпляр, вы можете найти дескриптор процесса для этого экземпляра и отправить ему сообщение для восстановления, если оно свернуто.

2 голосов
/ 20 июля 2010

Microsoft не безупречна, поэтому я предпочитаю старую школу:

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;

Теперь обработчик сообщений WM_KNOCK_KNOCK первого экземпляра выполняет процедуру пробуждения.что именно вы делаете, когда получаете WM_LBUTTONUP (или, возможно, WM_LBUTTONDBLCLK) в вашей оболочке Shell_NotifyIcon (Application.Restore, может быть?).Как сказал Крис Торнтон, не существует такого состояния, как «свернутый в трей», оно искусственное.


Откат: если утверждение не выполнено, обратите внимание, что код зависит только от функции класса ClassName, поэтому его можно легко удалить из FormCreate и вызвать до того, как приложение его создаст.

1 голос
/ 12 июля 2012
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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...