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

利用類別非靜態成員函數作為視窗處理函數的實作技巧

     編輯:VC 教學

核心概念

在 Windows 程式設計中,視窗處理函數必須是靜態函數或全域函數,因為系統呼叫時不會傳遞 this 指標。若想在類別中使用非靜態成員函數處理訊息,需透過「靜態橋接函數 + 實例指標儲存」的模式實現。

實作步驟

  1. 定義靜態處理函數:作為真正的視窗程序,符合 WNDPROC 簽名。
  2. 建立視窗時儲存 this 指標:呼叫 SetWindowLong(hWnd, GWL_USERDATA, (LONG)this) 將類別實例指標關聯至視窗。
  3. 靜態函數中取回指標並轉發:使用 GetWindowLong(hWnd, GWL_USERDATA) 取得實例指標,再呼叫非靜態成員函數處理具體邏輯。

程式碼範例

class SArea {
protected:
    HWND h_Wnd;
public:
    virtual HWND CreateSArea(LPCTSTR wndName, DWORD dwStyle, int x, int y, int w, int h, HWND hParent);
    static LRESULT CALLBACK SAreaProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    virtual void SProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};

HWND SArea::CreateSArea(LPCTSTR wndName, DWORD dwStyle, int x, int y, int w, int h, HWND hParent) {
    WNDCLASS wc;
    // 初始化 wc,設定 lpfnWndProc = SArea::SAreaProc
    ::RegisterClass(&wc);
    h_Wnd = ::CreateWindow(/* 參數省略 */);
    if (h_Wnd)
        ::SetWindowLong(h_Wnd, GWL_USERDATA, (LONG)this); // 關鍵:儲存 this 指標
    return h_Wnd;
}

LRESULT CALLBACK SArea::SAreaProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    SArea* pArea = NULL;
    // WM_NCCREATE/WM_CREATE 時 GWL_USERDATA 尚未設定,需跳過
    if (message != WM_NCCREATE && message != WM_CREATE)
        pArea = (SArea*)::GetWindowLong(hWnd, GWL_USERDATA);
    if (pArea)
        pArea->SProc(hWnd, message, wParam, lParam); // 轉發給非靜態函數
    return ::DefWindowProc(hWnd, message, wParam, lParam);
}

void SArea::SProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    // 具體訊息處理邏輯
}

關鍵點解析

  • GWL_USERDATA 是視窗結構預留的 32 位空間,專門用於儲存應用程式自訂資料(這裡存放 this)。
  • WM_NCCREATE 和 WM_CREATE 訊息到達時,SetWindowLong 可能尚未執行,因此必須在靜態函數開頭判斷並略過取指標動作,避免空指標呼叫。
  • 此模式廣泛應用於 MFC 的 CWnd::WindowProc 機制,也是物件導向封裝 Win32 API 的基石。

適用場景

自訂視窗類別、封裝 ActiveX 控制項、實作不依賴 MFC 的輕量級視窗封裝庫等。

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