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

MFC 中靈活使用自定義消息:跨類、跨進程通信完整指南

     編輯:VC 教學

自定義消息的必要性與挑戰

MFC 消息映射機制雖強大,但 ClassWizard 不支持直接添加用戶自定義消息,需手動添加代碼。本文系統講解自定義消息的定義、處理、映射,以及跨類、跨進程發送的完整方案。

標準四步實現流程

步驟一:定義消息 ID

#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()

系統唯一消息:RegisterWindowMessage

跨進程唯一標識:

static UINT WM_MY_MESSAGE = RegisterWindowMessage(_T("MyUniqueMessage"));

映射宏改用 ON_REGISTERED_MESSAGE(WM_MY_MESSAGE, OnMyMessage),其餘步驟相同。

發送消息的多種場景

1. 同進程內發送

PostMessage(WM_MY_MESSAGE, 0, 0);

2. 跨進程發送(帶超時防死鎖)

DWORD result;
SendMessageTimeout(wnd->m_hWnd, WM_MY_MESSAGE, 0, 0,
    SMTO_ABORTIFHUNG | SMTO_NORMAL, TIMEOUT_INTERVAL, &result);

SMTO_ABORTIFHUNG 避免目標進程掛起導致發送端無限等待。

3. 向其他類發送(視圖、框架、對話框、控件等)

核心思路:獲取目標類指針 → 調用其 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);
}

完整示例:多文檔程序中對話框向視圖發送消息

  1. 創建 MFC 多文檔專案 Message,默認設置。
  2. 主菜單添加「測試」彈出對話框,框架類添加 OnTest()。
  3. 資源創建對話框,ClassWizard 添加類 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);
    }
  4. Message.h 定義全局唯一消息:
    static UINT WM_MY_MESSAGE = RegisterWindowMessage(_T("Message"));
  5. 視圖類 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 繪製「消息響應!」
    
  6. 主框架 OnTest() 顯示對話框:
    #include "TestDialog.h"
    void CMainFrame::OnTest() { TestDialog dlg; dlg.DoModal(); }

運行程序,點擊菜單彈出對話框,點擊按鈕即可看到視圖類響應自定義消息並重繪。

總結

通過獲取目標類指針並調用其消息發送函數,配合註冊消息保證唯一性,可實現 MFC 架構下任意類之間、甚至跨進程的靈活消息通信,突破框架限制,避免死鎖風險。

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