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

深入剖析 MFC 消息映射機制

     編輯:VC 教學

一、消息映射機制詳解

MFC 的消息映射機制是視窗程式處理 Windows 訊息的核心。它避免了傳統虛函數表帶來的記憶體浪費,透過查表方式將訊息與處理函數關聯。以下以 CDrawView 類別響應滑鼠左鍵按下訊息 (WM_LBUTTONDOWN) 為例,說明完整流程。

1. 宣告訊息響應函數 (標頭檔 DrawView.h)

在 ClassWizard 維護的註釋巨集區塊中宣告函數原型:

//{{AFX_MSG(CDrawView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG

afx_msg 巨集標識這是一個訊息處理函數,註釋巨集讓 ClassWizard 能識別並維護此處代碼。

2. 實作消息映射 (原始檔 DrawView.cpp)

在 BEGIN_MESSAGE_MAP 與 END_MESSAGE_MAP 巨集之間建立映射關係:

BEGIN_MESSAGE_MAP(CDrawView, CView)
//{{AFX_MSG_MAP(CDrawView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

ON_WM_LBUTTONDOWN() 巨集將 WM_LBUTTONDOWN 訊息與 OnLButtonDown 函數綁定。其內部定義包含訊息碼、參數類型標誌及函數指標轉換,確保訊息到達時自動調用對應處理函數。

3. 編寫訊息處理代碼

ClassWizard 自動生成函數骨架,開發者填入具體邏輯:

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此加入訊息處理程式碼和/或呼叫預設值
    CView::OnLButtonDown(nFlags, point);
}

新增一個訊息響應需修改三處:標頭檔宣告、映射表項目、函數實作。

二、消息響應的底層運作方式

1. 虛函數方案的缺陷

若在基類為每種訊息定義虛函數,所有衍生類都將繼承龐大的虛函數表,嚴重浪費記憶體。MFC 採用消息映射機制解決此問題。

2. 消息映射的運作流程

  1. MFC 維護一張 HWND 到 CWnd* 的對照表。
  2. 收到訊息時,透過 HWND 查找對應的 C++ 物件指標。
  3. 基類利用此指標呼叫虛函數 WindowProc(),進而呼叫 OnWndMsg()。
  4. OnWndMsg() 根據訊息類型查找消息映射表(即標頭檔註釋巨集區塊與原始檔 BEGIN_MESSAGE_MAP 區塊)。
  5. 找到對應處理函數並調用;若衍生類未處理,則交由基類處理。

關鍵虛函數簽名:

virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);

三、繪圖裝置內容 (DC) 的三種獲取方式

1. 使用 SDK 風格 (C 風格 API)

HDC hdc = ::GetDC(m_hWnd);
MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, NULL);
LineTo(hdc, point.x, point.y);
::ReleaseDC(m_hWnd, hdc);

2. 使用 CDC 指標與 CWnd 成員函數

CDC* pDC = GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);

3. 使用 CClientDC 物件 (RAII 風格,推薦)

CClientDC dc(this); // 建構時自動 GetDC,解構時自動 ReleaseDC
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

CClientDC 封裝了獲取與釋放邏輯,程式碼更簡潔安全,是 MFC 繪圖的推薦做法。

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