2011-05-12 106 views
0

我有一個例行程序,看起來像這樣,在僞代碼:過濾Windows的消息隊列

while PeekMessage(Message, 0, 0, 0, PM_REMOVE) 
    HandleMessageAppropriately(Message) 

基本上,它經歷並拉起所有消息從隊列和調度它們。我無法改變這個例程。

我有一個場景,在這個例程中,如果它在某些條件下被調用,並且隊列中有一條消息表示用戶在恰好錯誤的時刻點擊了ESC,它可能導致程序崩潰。 (愛情競賽條件)

我不能改變上面的例程,但我可以改變調用它的代碼。有沒有什麼方法可以在運行之前立即執行某些操作,它會說「通過消息隊列並刪除所有鍵盤輸入消息,其中用戶按ESC,而不影響隊列中剩餘的項目或更改它們的順序「?

+1

看起來像有人一直在調用ProcessMessages! – 2011-05-12 22:23:10

+0

@大衛,是的,是的。 – 2011-05-12 22:31:31

回答

3

您可以使用PeekMessage中的範圍參數僅限於WM_CHAR消息,如果該字符不是ESC,則PM_NOREMOVE可以保持消息隊列完好無損;如果需要刪除該消息,則使用PM_REMOVE標誌重複該過程。不幸的是,沒有辦法查看隊列中第一個WM_CHAR。

+0

謝謝,這工作。這個解決方案在黑客身上真的感覺像是黑客攻擊,但它很有效。 – 2011-05-13 00:02:40

0

您可能最好將呼叫掛接到PeekMessages並將其替換爲您需要的版本。

你可以使用madshi的hooking例程,但這並不困難 - 我在Stack Overflow上發佈了一個簡單的鉤子例程。

如果代碼在您編譯的可執行模塊中運行,那麼您可以編譯取代PeekMessage的自定義版本的Windows.pas。當然,我猜你的代碼是Delphi。

3

這與臭名昭着的DoEvents調用完全相同,它讓很多VB6程序員陷入困境。因爲ESC按鍵肯定會關閉一個窗口,讓代碼在沒有用戶界面的情況下循環運行。結果總是很差。

您不會在這裏亂搞,您在進入此循環之前調用EnableWindow(hWnd,FALSE),以在不應關閉的窗口上禁用輸入。現在你不再在意消息隊列中的內容了。對話框完全一樣。

請勿在模態循環中進行打印。讓它變得模式化,讓用戶也很明白。

+0

是的,這幾乎就是發生了什麼,除了代碼是Delphi而不是VB。 (不幸的是,德爾菲團隊爲了更容易吸引VB編碼器,將標準庫中的等效方法放入標準庫中)。遺憾的是,由於遺留兼容性的原因,我無法將其變爲真正的模式。 – 2011-05-13 00:02:08