2012-12-18 28 views

回答

17

這是我拉過一個線程的隊列中的消息:

while GetMessage(Msg, 0, 0, 0) and not Terminated do begin 
    Try 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    Except 
    Application.HandleException(Self); 
    End; 
end; 

使用Application.ProcessMessages將拉動調用線程的隊列中的消息。但在消息循環中使用它並不合適,因爲它不會阻塞。這就是爲什麼你使用GetMessage。它會阻止隊列是否爲空。並且Application.ProcessMessages也稱其他TApplication方法不被設計爲線程安全。所以有很多理由不會從主線程以外的線程調用它。

當你需要終止線程,那麼我這樣做:

Terminate; 
PostThreadMessage(ThreadID, WM_NULL, 0, 0); 
//wake the thread so that it can notice that it has terminated 

這一切都不是OTL具體。此代碼全部用於生活在TThread後代。但是,這些想法是可以轉讓的。


在註釋中,您指出要運行繁忙的非阻塞消息循環。你會使用PeekMessage

while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin 
    Try 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    Except 
    Application.HandleException(Self); 
    End; 
end; 
+0

這看起來很複雜。它可以放在一個程序中嗎? 像這樣:「while IHTMLDocument2.readyState <>'complete'do MessageLoop;」 –

+0

這將是一個繁忙的循環,有點不同。我的更新顯示瞭如何用'PeekMessage'做到這一點。在理想的世界中,你不會這麼做。繁忙的循環無用地消耗CPU週期。在理想的世界中,您會收到通知說您的文檔已準備就緒。 –

+0

@DavidHeffernan看起來'而GetMessage'不是推薦的方式? https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx – SOUser

3

您可以構建一個類似於Application.Run中的循環。

您可以致電PeekMessage,它檢查消息是否可用。 PeekMessage檢查當前線程的消息隊列,因此如果您在線程中使用它,它會檢查線程的消息隊列(可以使用PostThreadMessage向其發送消息)。

而不是PeekMessage,您還可以使用GetMessage,它等待,直到收到一條消息。 GetMessage 返回0 返回false*)

當它得到一個WM_QUIT消息,這也是終止消息循環的信號。之後再次調用GetMessage是很冒險的,因爲它可能不會收到其他消息,並且可能會阻止您的應用程序正確關閉,因爲它阻塞了。

Application.ProcessMessages確實不是很安全,因爲它會執行很多特定於主線程的額外功能。一方面,一旦消息隊列爲空,它就會觸發Application.OnIdle,這意味着它在線程消息隊列爲空時(線程消息隊列爲空)調用(問題1),並且不允許任何VCL在事件中的交互。

* 關於GetMessage的返回值:我注意到Delphi實現了GetMessage作爲返回LongBool。但是,實際返回值是一個整數。它在WM_QUIT的情況下返回0,在發生錯誤時返回-1,在其他情況下返回非零。 Microsoft states

因爲返回值可以是零,零,或-1,避免像 驗證碼:

while (GetMessage(lpMsg, hWnd, 0, 0)) ... 

不幸的是,你必須根據不同的別名導入的GetMessage到正確使用它。

+0

而不是重新導入,您可以只輸入GetMessage的結果。 –