Share via


在 Win32 和 WPF 之間共用訊息迴圈

更新:2007 年 11 月

本主題說明如何透過使用 Dispatcher 中現有的訊息迴圈 (Loop) 公開,或是在互通性程式碼的 Win32 端建立個別訊息迴圈,以便實作用來與 Windows Presentation Foundation (WPF) 互通的訊息迴圈。

ComponentDispatcher 和訊息迴圈

互通性和鍵盤事件支援的一般案例是實作 IKeyboardInputSink,或是從已經實作 IKeyboardInputSink 的類別 (例如 HwndSourceHwndHost) 進行子類別化 (Subclass)。不過,鍵盤接收器支援無法處理跨互通界限傳送及接收訊息時,可能產生的所有訊息迴圈需求。為了協助應用程式訊息迴圈架構的成形,Windows Presentation Foundation (WPF) 提供了 ComponentDispatcher 類別,用以定義供訊息迴圈遵守的簡單通訊協定 (Protocol)。

ComponentDispatcher 是公開幾個成員的靜態類別。每個方法的範圍都隱含繫結至呼叫端執行緒。訊息迴圈必須在關鍵時間 (如下一節所定義) 呼叫部分 API。

ComponentDispatcher 提供其他元件 (例如鍵盤接收器) 可以接聽的事件。Dispatcher 類別會按照適當的順序呼叫所有適當的 ComponentDispatcher 方法。若實作的是您自己的訊息,便由您的程式碼負責以類似的方式呼叫 ComponentDispatcher 方法。

在執行緒上呼叫 ComponentDispatcher 方法只會叫用 (Invoke) 已在該執行緒上註冊的事件處理常式 (Event Handler)。

撰寫訊息迴圈

以下提供一份檢查清單,其中列出自行撰寫訊息迴圈時所要使用的 ComponentDispatcher 成員:

  • PushModal:訊息迴圈應該呼叫這個成員,表示執行緒是強制回應。

  • PopModal:訊息迴圈應該呼叫這個成員,表示執行緒已還原為非強制回應。

  • RaiseIdle:訊息迴圈應該呼叫這個成員,表示 ComponentDispatcher 應該引發 ThreadIdle 事件。如果 IsThreadModal 為 true,ComponentDispatcher 就不會引發 ThreadIdle,但是訊息迴圈還是可以選擇呼叫 RaiseIdle,即使ComponentDispatcher 在強制回應狀態中無法回應呼叫。

  • RaiseThreadMessage:訊息迴圈應該呼叫這個成員,表示有新的訊息。傳回的值會指出 ComponentDispatcher 事件的接聽程式 (Listener) 是否已處理該訊息。如果 RaiseThreadMessage 傳回 true (已處理),發送器應該不會對訊息執行其他動作。如果傳回值是 false,則發送器應該會呼叫 Win32 函式 TranslateMessage,然後再呼叫 DispatchMessage

使用 ComponentDispatcher 和現有訊息處理

以下提供一份檢查清單,其中列出依賴固有 WPF 訊息迴圈時所要使用的 ComponentDispatcher 成員。

如果在 ThreadFilterMessage 事件或 ThreadPreprocessMessage 事件之後,事件資料中以傳址方式傳遞的 handled 參數為 true,就會將訊息視為已經處理。若 handled 為 true,事件處理常式應該忽略該訊息,因為這表示不同的處理常式已先處理該訊息。這兩個事件的事件處理常式都可以修改該訊息。發送器應該發送修改過的訊息,而不是未更動過的原始訊息。ThreadPreprocessMessage 會傳送給所有接聽程式,但在架構目的中,應該只有內含訊息鎖定之 HWND 的最上層視窗 (Top-Level Window) 才能叫用程式碼來回應訊息。

HwndSource 處理 ComponentDispatcher 事件的方式

如果 HwndSource 是最上層視窗 (無父代 HWND),它會註冊 ComponentDispatcher。如果引發 ThreadPreprocessMessage,而且訊息是要用於 HwndSource 或子視窗,HwndSource 便會呼叫其 IKeyboardInputSink.TranslateAcceleratorTranslateCharOnMnemonic 鍵盤接收器序列。

如果 HwndSource 不是最上層視窗 (有父代 HWND),則不會進行任何處理動作。只有最上層視窗才能執行處理作業,而且任何互通性案例應該都有可以支援鍵盤接收器的最上層視窗。

如果呼叫 HwndSource 上的 WndProc 之前沒有先呼叫適當的鍵盤接收器方法,應用程式會收到較高層級的鍵盤事件,例如 KeyDown。不過,系統不會呼叫任何鍵盤接收器方法,而無法提供需要的鍵盤輸入模型功能,例如便捷鍵 (Access Key) 支援。發生這種情況的原因可能是訊息迴圈未正確通知 ComponentDispatcher 上的相關執行緒,或是父代 HWND 未叫用適當的鍵盤接收器回應。

如果您使用 AddHook 方法加入進入鍵盤接收器之訊息的攔截程式 (Hook),該訊息可能不會傳送到 HWND。這個訊息可能已經直接在訊息幫浦層級加以處理,而且不會送出至 DispatchMessage 函式。

請參閱

概念

WPF 和 Win32 互通性概觀

執行緒模型

輸入概觀

參考

ComponentDispatcher

IKeyboardInputSink