首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 鉤子機制深度解析:多重 CBT 鉤子共存與 MFC 內部原理

     編輯:關於VC++

問題:能否安裝多個 WH_CBT 鉤子?

答案是肯定的。Windows 鉤子鏈設計為支援同類型多個鉤子共存,關鍵在於正確呼叫 CallNextHookEx 將控制權傳遞給下一個鉤子。

安裝鉤子標準流程

HHOOK hOldHook; // 全域變數保存舊鉤子控制代碼

hOldHook = SetWindowsHookEx(WH_CBT, MyCbtProc, hInstance, threadId);

LRESULT CALLBACK MyCbtProc(int code, WPARAM wp, LPARAM lp)
{
    if (code == HCBT_CREATEWND) {
        // 自訂處理...
    }
    return CallNextHookEx(hOldHook, code, wp, lp); // 必須呼叫
}

MFC 如何使用 CBT 鉤子

MFC 利用 CBT 鉤子監視視窗建立過程,在視窗收到任何訊息前將 CWnd 物件附加到 HWND 並完成子類化。

關鍵步驟

  1. CWnd::CreateEx 呼叫 AfxHookWindowCreate(this),安裝 CBT 鉤子 _AfxCbtFilterHook,並在執行緒狀態 _AFX_THREAD_STATE 中保存 m_pWndInit = this。
  2. 呼叫 ::CreateWindowEx 建立視窗。
  3. Windows 在發送 WM_CREATE 等訊息前,以 HCBT_CREATEWND 呼叫 CBT 鉤子。
  4. _AfxCbtFilterHook 取得 m_pWndInit 指標,呼叫 Attach 並設定 AfxWndProc 完成子類化。
  5. ::CreateWindowEx 返回,CWnd::CreateEx 呼叫 AfxUnhookWindowCreate 移除鉤子並清空 m_pWndInit。

為何不直接在 CreateEx 子類化?

因為 ::CreateWindowEx 在返回前已發送 WM_GETMINMAXINFO、WM_NCCREATE、WM_CREATE 等訊息。若不在訊息發送前附加 CWnd,這些早期訊息將遺失。CBT 鉤子正是在建立視窗後、發送訊息前的唯一切入點。

多重鉤子共存注意事項

  • 只要每個鉤子都正確呼叫 CallNextHookEx,即可安裝任意數量同類型鉤子。
  • 若您的鉤子需傳遞自訂資料給鉤子程序,SetWindowsHookEx 無 void* 參數,唯一方式是使用執行緒區域儲存(TLS)或全域變數。MFC 使用執行緒狀態結構達成此目的。

托管程式碼取得 HINSTANCE

.NET 無 AfxGetInstanceHandle 對應物。正確做法:

Type t = myObj.GetType();           // 或 typeof(MyApp)
Module m = t.Module;
IntPtr h = Marshal.GetHINSTANCE(m);

必須使用「呼叫模組中定義的型別」,否則會取得錯誤模組(如 String 會取得 mscorlib)。

MFC CString 轉換為 Managed String

String 為不可變型別,修改字串實為建立新實例。對應 C# ref string,C++/CLI 可用 String^%(追蹤參考)或 String*&(指標參考):

int ErrorMessage(String^% msg) { msg = "new value"; return -1; }

若需從資源檔載入字串,.NET 採用 .resx + ResourceManager 機制;若暫時沿用 RC 檔,可先以 CString 載入再轉換:

CString s; HINSTANCE h = GetModuleHandle(_T("MyLib.dll")); s.LoadString(h, id);
String^ managed = gcnew String(s);

結語

理解鉤子鏈、MFC 視窗建立機制、托管/非托管互操作細節,能幫助開發者正確使用進階 Windows 功能並避免常見陷阱。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved