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

將非 MFC 窗口回調封裝為 C++ 類成員函數

     編輯:關於VC++

背景動機

傳統非 MFC Windows 程式習慣將窗口過程與消息處理函數寫為全局函數。為了實現面向對象封裝,本文提出一種通過動態生成機器碼(Hook 代碼塊)的技術,將窗口回調函數轉發至 C++ 類的虛擬成員函數,使每個窗口類擁有獨立的 WndProc 實現。

核心類設計:CWndProc

頭文件

class CWndProc {
protected:
    CWndProc(); virtual ~CWndProc();
    virtual LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) = 0;
private:
    char m_hook[40];          // 機器碼存儲區
protected:
    WNDPROC m_pfnWndProc;     // 指向 Hook 代碼塊入口
};

實現原理

在構造函數中:

  1. 複製預定義的 x86 機器碼模板到 m_hook
  2. 修改模板中的 this 指針為當前對象地址
  3. 計算虛函數表中 WndProc 的相對偏移,修正 call 指令目標
  4. 將 m_pfnWndProc 指向修改後的代碼塊

機器碼模板功能:依調用約定從堆棧取出 hwnd, uMsg, wParam, lParam,壓入 this,調用派生類的 WndProc,最後 ret 10h 清理堆棧。

關鍵實現代碼

CWndProc::CWndProc() {
    CopyMemory(m_hook, g_hook, sizeof(g_hook));
    char* p = m_hook + 19;                 // 定位 mov ecx, 0
    *((unsigned int*)p) = (unsigned int)this; // 替換為實際 this
    LRESULT (CALLBACK CWndProc::*pfn)(HWND, UINT, WPARAM, LPARAM) = WndProc;
    p = m_hook + 27;                       // 定位 call 指令
    __asm {
        mov eax, pfn; sub eax, 4; mov edi, p;
        sub eax, edi; mov [edi], eax;      // 計算相對偏移並回填
    }
    m_pfnWndProc = (WNDPROC)&m_hook[0];
}

使用範例

派生類 CDialog 繼承 CWndProc,實現 WndProc 虛函數;進一步派生 CFormDlg、CInputDlg、CAboutDlg 等具體對話框類,皆可直接使用成員函數處理消息。示例工程在 Windows 2000 + VC++ 6.0 下編譯通過。

技術優勢與注意事項

  • 完全封裝,無需全局窗口過程
  • 每個對象擁有獨立 Hook 代碼塊,線程安全
  • 依賴 VC++ 6.0 特定虛表佈局,移植性受限
  • 需確保 m_hook 所在內存頁面可執行(DEP 環境需調整)

本文配套源碼包含完整實現與示例工程。

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