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

Windows SDK 筆記(三):控制項訊息處理函式子類別化技術詳解

     編輯:關於VC++

子類別化核心概念

控制項訊息處理函式由系統定義,通常無需自行提供。但需特殊控制時,可提供處理函式替換原有函式,處理完成後再呼叫控制項預設處理——這就是「子類別化」技術。

核心 API 函式

1. 視窗長整數存取:GetWindowLong / SetWindowLong

LONG GetWindowLong(HWND hWnd, int nIndex);
LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);

可存取的索引值(nIndex):

索引意義
GWL_EXSTYLE擴充視窗樣式
GWL_STYLE視窗樣式
GWL_WNDPROC訊息處理函式指標
GWL_HINSTANCE執行個體控制代碼
GWL_ID視窗 ID
GWL_USERDATA使用者自訂資料
DWL_DLGPROC對話方塊訊息處理函式
DWL_MSGRESULT訊息處理結果
DWL_USER對話方塊使用者資料

替換控制項訊息處理函式:

OldMsgProc = (WNDPROC)SetWindowLong(hControlWnd, GWL_WNDPROC, (LONG)MyMsgProc);

原處理函式被 OldMsgProc 記錄。

2. 呼叫前一個處理函式:CallWindowProc

LRESULT CallWindowProc(
    WNDPROC lpPrevWndFunc,  // 前一個處理函式
    HWND hWnd,              // 視窗控制代碼
    UINT Msg,               // 訊息
    WPARAM wParam,          // 參數 1
    LPARAM lParam);         // 參數 2

完整實作範例

1. 定義新處理函式

// 記錄原處理函式的全域變數
WNDPROC OldMsgProc;

// 新訊息處理函式
LRESULT MyMsgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_LBUTTONDOWN:
            ::MessageBox(NULL, "click!", "", MB_OK);
            break;
    }
    // 呼叫控制項原始訊息處理函式
    return CallWindowProc(OldMsgProc, hwnd, message, wParam, lParam);
}

2. 視窗建立後替換處理函式

case WM_CREATE:
{
    HWND hControlWnd = CreateWindowEx(0, "BUTTON",
        TEXT("按鈕(&A)"),
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
        10, 10, 100, 100,
        hwnd,
        (HMENU)1000,  // 控制項 ID
        ((LPCREATESTRUCT)lParam)->hInstance,
        NULL);

    // 嵌入新訊息處理函式
    OldMsgProc = (WNDPROC)SetWindowLong(hControlWnd, GWL_WNDPROC, (LONG)MyMsgProc);
}
return 0;

子類別化 vs 超類別化對照

特性子類別化超類別化
定義修改現有視窗實例的處理函式以系統類別為基礎註冊新類別
作用範圍單一視窗實例所有該新類別的實例
實作方式SetWindowLong(GWL_WNDPROC)GetClassInfo + 修改 + RegisterClass
繼承系統行為透過 CallWindowProc透過 CallWindowProc 或 DefWindowProc
適用場景少數特定控制項需特殊行為大量同類控制項共享自訂行為

64 位元相容性注意事項

Win64 下指標為 64 位元,需使用 GetWindowLongPtr/SetWindowLongPtr 與 GWLP_WNDPROC:

#ifdef _WIN64
    #define SetWindowLongPtrGWL SetWindowLongPtr
    #define GetWindowLongPtrGWL GetWindowLongPtr
    #define GWLP_WNDPROC GWLP_WNDPROC
#else
    #define SetWindowLongPtrGWL SetWindowLong
    #define GetWindowLongPtrGWL GetWindowLong
    #define GWLP_WNDPROC GWL_WNDPROC
#endif

OldMsgProc = (WNDPROC)SetWindowLongPtrGWL(hControlWnd, GWLP_WNDPROC, (LONG_PTR)MyMsgProc);

常見應用場景

  • 輸入限制:Edit 控制項僅接受數字/特定格式
  • 視覺客製:Button 繪製非標準外觀(Owner Draw)
  • 行為擴充:ListBox 攔截雙擊執行自訂動作
  • 存取攔截:記錄控制項所有訊息用於除錯/分析
  • 無障礙支援:增強鍵盤導航、螢幕閱讀器相容性

除錯技巧

  1. 使用 Spy++ 觀察訊息流向確認子類別化生效
  2. 在新處理函式入口設中斷點驗證呼叫順序
  3. 確保 CallWindowProc 參數正確傳遞,避免堆疊損壞
  4. 記錄 OldMsgProc 非 NULL 驗證原函式成功取得
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved