MFC 消息映射機制雖強大,但 ClassWizard 不支持直接添加用戶自定義消息,需手動添加代碼。本文系統講解自定義消息的定義、處理、映射,以及跨類、跨進程發送的完整方案。
#define WM_MY_MESSAGE (WM_USER + 100)
建議: 使用 WM_USER + 100 以上,避免與新控件內部消息衝突。
LRESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam) {
// 處理自定義消息
return 0;
}
簽名固定:返回 LRESULT,參數 WPARAM、LPARAM。
class CMainFrame : public CMDIFrameWnd {
// ...
protected:
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); // 新增
// }}AFX_MSG
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) // 關鍵宏
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
跨進程唯一標識:
static UINT WM_MY_MESSAGE = RegisterWindowMessage(_T("MyUniqueMessage"));
映射宏改用 ON_REGISTERED_MESSAGE(WM_MY_MESSAGE, OnMyMessage),其餘步驟相同。
PostMessage(WM_MY_MESSAGE, 0, 0);
DWORD result;
SendMessageTimeout(wnd->m_hWnd, WM_MY_MESSAGE, 0, 0,
SMTO_ABORTIFHUNG | SMTO_NORMAL, TIMEOUT_INTERVAL, &result);
SMTO_ABORTIFHUNG 避免目標進程掛起導致發送端無限等待。
核心思路:獲取目標類指針 → 調用其 PostMessage/SendMessage。
// 視圖類定義消息映射與處理函數
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam) { ... }
// 主框架發送
void CMainFrame::OnTest() {
CView* pActive = GetActiveView();
if (pActive) pActive->PostMessage(WM_MY_MESSAGE, 0, 0);
}
void CMainFrame::OnTest() {
CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd* pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
CView* pView = pChild->GetActiveView();
if (pView) pView->PostMessage(WM_MY_MESSAGE, 0, 0);
}
void CMessageView::OnTest() {
CFrameWnd* pActive = GetActiveFrame();
if (pActive != this) pActive->PostMessage(WM_MY_MESSAGE, 0, 0);
}
Message,默認設置。OnTest()。TestDialog,按鈕處理 OnDialogTest()。
void TestDialog::OnDialogTest() {
CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
CMDIChildWnd* pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
CView* pView = pChild->GetActiveView();
if (pView) pView->PostMessage(WM_MY_MESSAGE, 0, 0);
}
Message.h 定義全局唯一消息:
static UINT WM_MY_MESSAGE = RegisterWindowMessage(_T("Message"));
CMessageView 添加消息映射與處理:
// .h
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
// .cpp
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam) {
CRect rect; GetClientRect(&rect);
InvalidateRect(&rect);
test = !test;
return 0;
}
// 構造函數初始化 test=FALSE
// OnDraw 中根據 test 繪製「消息響應!」
OnTest() 顯示對話框:
#include "TestDialog.h"
void CMainFrame::OnTest() { TestDialog dlg; dlg.DoModal(); }
運行程序,點擊菜單彈出對話框,點擊按鈕即可看到視圖類響應自定義消息並重繪。
通過獲取目標類指針並調用其消息發送函數,配合註冊消息保證唯一性,可實現 MFC 架構下任意類之間、甚至跨進程的靈活消息通信,突破框架限制,避免死鎖風險。