2013-03-02 26 views
1

我有一個應用程序在主窗體的OnCreate期間檢查應用程序的另一個實例是否已通過創建互斥體運行。如果是,則第二個實例將消息傳遞給第一個實例,然後關閉它。它工作正常,除了第二個應用程序的一小竅門,它在屏幕關閉之前在屏幕上快速閃爍。停止窗體幾乎立即關閉第二個應用程序實例時在屏幕上快速閃爍

我有一個醜陋的啓動應用程序與主窗體WindowState設置爲wsMinimize,然後使用延遲1ms的計時器來最大化窗體。但這似乎是一個可怕的黑客。

有什麼更好的點子?

procedure TMyAwesomeForm.FormCreate(Sender: TObject); 
var 
    h: HWND; 
begin 
    // Try to create mutex 
    if CreateMutex(nil, True, '6EACD0BF-F3E0-44D9-91E7-47467B5A2B6A') = 0 then 
    RaiseLastOSError; 

    // If application already running 
    if GetLastError = ERROR_ALREADY_EXISTS then 
    begin 
    // Prevent this instance from being the receipient of it's own message by changing form name 
    MyAwesomeForm.Name := 'KillMe'; 

    // If this instance was started with parameters: 
    if ParamCount > 0 then 
    begin 
     h := FindWindow(nil, 'MyAwesomeForm'); 

     //Pass the parameter to original application 
     SendMessage(h, WM_MY_MESSAGE, strtoint(ParamStr(1)),0); 
    end; 

    // Shut this instance down - there can be only one 
    Application.Terminate; 
    end; 

    // Create Jump Lists  
    JumpList := TJumpList.Create; 
    JumpList.ApplicationId := 'TaskbarDemo.Unique.Id'; 
    JumpList.DeleteList; 
    CreateJList(); 
end; 
+3

移動你的代碼在什麼地方真正被創建的形式,在'Application.CreateForm'之前被調用,在* .dpr文件。 – TLama 2013-03-02 01:08:18

+0

這與[此問題](http://stackoverflow.com/q/15136960/62576)的副本非常接近。那裏的答案可能會有所幫助。 (你檢查太遲了 - 當你點擊'FormCreate'時,已經太遲了,而'Application.Terminate'只是向主窗口發送'WM_QUIT'消息,你需要檢查以前的實例在'.dpr'文件中,而不是在調用'Application.Initialize'之前。) – 2013-03-02 01:12:42

回答

4

不要在窗體類中執行你的檢查,因爲表單會被創建出來。

恕我直言,與你一樣執行檢查的更好的地方是.dpr文件本身。

例如:

program Project3; 

uses 
    Forms, 
    Windows, //<--- new citizens here 
    SysUtils, 
    Messages, 
    Unit1 in 'Unit1.pas' {Form1}; 

{$R *.res} 

function IsAlreadyRunning: Boolean; 
var 
    h: HWND; 
begin 
    //no comments, sorry, but I don't use comments to explain what the 
    //code explains by itself. 
    Result := False; 

    if CreateMutex(nil, True, '6EACD0BF-F3E0-44D9-91E7-47467B5A2B6A') = 0 then 
    RaiseLastOSError; 

    if GetLastError = ERROR_ALREADY_EXISTS then 
    begin 
    if ParamCount > 0 then 
    begin 
     h := FindWindow(nil, 'MyAwesomeForm'); 
     if h <> 0 then 
     PostMessage(h, WM_MY_MESSAGE, strtoint(ParamStr(1)),0); 
     Result := True; 
    end; 
    end; 
end; 

begin 
    if not IsAlreadyRunning then 
    begin 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TForm1, Form1); 
    Application.Run; 
    end; 
end. 
+0

而不是發送消息而是發送消息,如果消息接收器掛起其進程,它可能會阻止此初始化。還要將'wParam'參數轉換爲正確的'WPARAM'類型。最後,'IsAlreadyRunning'不是函數的好名字,它甚至不檢查窗口是否被找到,即使FindWindow返回0(NULL),它也會發送消息。 – TLama 2013-03-02 01:41:38

+0

@TLama我剛剛從問題中移動代碼以顯示避免表單顯示的位置,但是您是對的,我很懶,所以我添加了一個檢查並更改爲PostMessage而不是SendMessage。按照WPAREM的轉換,恕我直言,這是不需要的,因爲編譯器總是爲你做。 – jachguate 2013-03-02 02:08:40

+0

非常感謝。這是整理出來的。我不知道我甚至可以像這樣在dpr文件中放入代碼。試圖教你自己的樂趣!我試圖提高你的解決方案,但可悲的是我的聲譽是不夠的。 – user2125574 2013-03-03 00:32:01

相關問題