[英]How can I keep an event from being delivered to the GUI until my code finished running?
我安裝了這樣的全局鼠標鈎子函數:
mouseEventHook = ::SetWindowsHookEx( WH_MOUSE_LL, mouseEventHookFn, thisModule, 0 );
掛鈎函數如下所示:
RESULT CALLBACK mouseEventHookFn( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION ) {
PMSLLHOOKSTRUCT mi = (PMSLLHOOKSTRUCT)lParam;
// .. do interesting stuff ..
}
return ::CallNextHookEx( mouseEventHook, code, wParam, lParam );
}
現在,我的問題是我無法控制“做有趣的事情”部分需要多長時間。 特別是,它可能需要比Windows注冊表中定義的LowLevelHooksTimeout更長的時間。 這意味着,至少在Windows XP上,系統不再將鼠標事件傳遞給我的掛鈎函數。 我想避免這種情況,但與此同時,我需要在目標GUI接收事件之前進行“有趣的事情”部分。
我試圖通過在單獨的線程中進行“有趣的工作”來解決此問題,以便上面的mouseEventHookFn
可以將消息發布到工作線程,然后執行return 1;
立即執行(這結束了掛鈎函數,但避免了將事件傳遞給GUI)。 想法是,工作線程完成后將自行執行CallNextHookEx
調用。
但是,這會導致CallNextHookEx
內部崩潰(實際上,崩潰發生在名為PhkNextValid
的內部函數內部。我認為從鈎子函數外部調用CallNextHookEx
是不安全的,這是真的嗎?
如果是這樣,其他人是否知道在GUI接收事件之前如何運行代碼(需要與應用程序的GUI線程進行交互) 並避免鈎子函數阻塞太長時間?
沒有解決方法,您必須使代碼更快。 這些掛鈎可能對用戶界面的響應能力非常不利,Windows確保行為不端的掛鈎進入地窖。 即使超時是可配置的,也永遠不會記錄下來。 那會打敗首先超時的目的。
為什么要使用鼠標事件掛鈎? 您是在一般地還是在特定窗口上鈎住鼠標? 如果用於特定窗口,則需要-而不是使用鈎子-實際上是目標窗口的子類。
這通常是一個兩階段的進程-掛鈎總是需要在dll中,因為掛鈎需要在實際處理消息的進程(和線程)的上下文中執行。
因此,您首先編寫一個鈎子dll,該鈎子dll在發送消息時會調用HWND上的SetWindowLong,以用新的窗口proc替換GWL_WINDOWPROC。
在WindowProc中,您可以花很長時間來處理消息。
假設從鈎子函數外部調用CallNextHookEx是不安全的,這是真的嗎?
我相信這是真的。
由於可以通過低級鼠標鈎子接收到的操作數量是有限的,因此只要長時間運行的操作完成,就可以將它們放到隊列中以重新發布到接收窗口中。 如果將長時間運行的線程放在另一個線程上,則不會“鎖定” UI,而只會“吃掉”或“推遲”用戶操作。 返回1以防止發生其他掛鈎。 使用布爾值標志來表示您是要收集事件(因為必須運行長時間運行的操作)還是重新發布事件(因此不應該掛接它們)。
您要取消的系統中可能沒有(m)其他任何低級掛鈎,但是您應該根據情況徹底測試此機制。 我僅用它來阻止操作(殺死鼠標右鍵)而不是推遲操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.