2010-07-20 8 views
1

나는 트레이 아이콘으로 최소화 된 델파이 앱을 가지고있다. 트레이 아이콘을 두 번 클릭하면 응용 프로그램이 모달이 아닌 사용자 인터페이스 양식을 엽니 다.트레이에서 실행중인 앱을 다시 활성화하는 가장 좋은 방법은 무엇입니까?

앱이 이미 실행 중인지 여부를 감지하기 위해 로직을 추가했습니다. 실행 중이 지 않으면 시작되어 트레이로 넘어갑니다.

이미 실행중인 경우 컨트롤을 첫 번째 인스턴스로 전달하고 넌 모달 폼을 연 다음 종료합니다 (두 번째 인스턴스). 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

TIA R

+2

시스템 트레이와 관련이 없습니다. 솔루션은 최소화 된 일반 창이면 동일합니다. 또는 열려 있지만 다른 창 뒤에 묻혀 있습니다. –

답변

2

마이크로 소프트 방법은 완벽하지 않다, 그래서 내가 옛날 선호합니까 :

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 첫 번째 인스턴스의 메시지 핸들러가 웨이크 업 루틴을 수행합니다.


내가 당신의 Shell_NotifyIcon 래퍼에서 (아마도 또는 WM_LBUTTONDBLCLK) WM_LBUTTONUP를받을 때 정확하게 당신이 무엇 작은 실마리가 (아마도 Application.Restore을?). 크리스 손튼 (Chris Thornton)이 말했듯이, '쟁반에 최소화'된 국가는 없기 때문에 그것은 인공적이다.


대체 : 주장이 실패 할 경우, 코드는 응용 프로그램을 만들기 전에 그렇게 쉽게 FormCreate 밖으로 이동하고 호출 할 수있는 수준의 기능 ClassName에만 의존 것을 확인합니다.

+0

거의 다 왔어. 첫 번째 인스턴스에서 메시지를 처리하고, 양식을 표시하고, BringToFront, SetFocus를 호출합니다. 그러나 폼을 최상위로 표시하거나 포커스를 가져올 수 없습니다. – rossmcm

+0

그리고 왜 42? 더글러스 애덤스? – rossmcm

+0

메시지를 wm_user + 으로 하드 코드하면 다른 응용 프로그램과 충돌 할 가능성이 있으므로 – Jherico

5

주어진 애플리케이션의 다른 인스턴스의 검출 recommended 방법은 두 번째 인스턴스에 오류가 유발되도록 명명 된 뮤텍스를 생성하거나 잘 알려진 위치에있는 파일을 잠그는 것을 애플리케이션 인 동일한 뮤텍스를 만들거나 동일한 파일을 잠글려고 할 때 다른 인스턴스가 실행 중임을 알게되면 해당 인스턴스에 대한 프로세스 핸들을 찾고 최소화 된 경우 복원 할 메시지를 보낼 수 있습니다.

+1

다른 인스턴스를 앞에 가져 오기 전에 AllowSetForegroundWindow를 호출해야합니다. – glob

+0

AllowSetForegroundWindow가 선언 된 위치를 찾을 수 없습니다 ...? – rossmcm

+0

뮤텍스보다 더 나은 선택이 명명 된 이벤트 (Windows 이벤트 객체가 아닌 Delphi 이벤트 메소드)입니까? 실행중인 응용 프로그램을 감지하고 감지하는 데 사용될 수 있습니다. – dummzeuch

1
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. 
관련 문제