簡體   English   中英

在代碼運行完畢之前,如何防止事件傳遞到GUI?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM