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

Windows 消息機制深度解析:從消息結構到消息循環的完整鏈路

     編輯:關於C語言

一、消息的組成

每條消息是一個 MSG 結構體:

typedef struct tagMSG { 
    HWND hwnd;        // 接收窗口句柄 
    UINT message;     // 消息標識 (WM_XXX) 
    WPARAM wParam;    // 參數 1 (消息特定) 
    LPARAM lParam;    // 參數 2 (消息特定) 
    DWORD time;       // 投遞時間 
    POINT pt;         // 滑鼠座標 
} MSG;
  • 消息分類:系統定義(WM_PAINT、WM_COMMAND...)、用戶自定義(WM_USER+、RegisterWindowMessage)。
  • 參數語義:如 WM_COMMAND,HIWORD(wParam) 為通知碼,LOWORD(wParam) 為控件/菜單 ID,lParam 為控件句柄。

二、消息路由:誰來處理?

  • 每個窗口擁有窗口過程 WNDPROC(回調函數)。
  • 系統將消息投遞到目標窗口的 WNDPROC。
  • 開發者在 WNDPROC 中 switch(message) 分發處理感興趣的消息。
  • 默認窗口過程 DefWindowProc 處理未捕獲消息(繪製邊框、移動、最小化等),保證基本窗口行為。

偽代碼:窗口過程

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { 
    switch (msg) { 
        case WM_PAINT: 
            OnPaint(hwnd); return 0; 
        case WM_LBUTTONDOWN: 
            OnLButtonDown(hwnd, wp, lp); return 0; 
        case WM_DESTROY: 
            PostQuitMessage(0); return 0; 
        default: 
            return DefWindowProc(hwnd, msg, wp, lp); 
    } 
}

三、消息隊列與消息循環

系統級隊列

  • 硬件輸入(鍵盤/滑鼠)→ 驅動程序 → 系統消息隊列(原始輸入)。
  • 系統將消息分發到線程消息隊列(每個 GUI 線程一個)。

應用級消息循環(WinMain 核心)

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) { 
    // 註冊窗口類、創建窗口... 
    MSG msg; 
    while (GetMessage(&msg, NULL, 0, 0)) { // 阻塞等待消息 
        TranslateMessage(&msg); // 虛擬鍵 → 字符消息 (WM_KEYDOWN → WM_CHAR) 
        DispatchMessage(&msg);  // 投遞到窗口過程 
    } 
    return (int)msg.wParam; 
}

關鍵點

  • GetMessage 返回 0 時(收到 WM_QUIT)循環結束。
  • PeekMessage 非阻塞輪詢,適用於遊戲主循環/後台任務。
  • TranslateMessage 僅處理鍵盤消息,將虛擬鍵碼翻譯為字符消息。
  • DispatchMessage 根據 msg.hwnd 查找窗口類關聯的 WNDPROC 並調用。

四、消息分類:排隊 vs 非排隊

五、MFC 的消息映射機制(封裝層)

BEGIN_MESSAGE_MAP(CMyView, CView) 
    ON_WM_PAINT() 
    ON_COMMAND(ID_FILE_NEW, OnFileNew) 
    ON_BN_CLICKED(IDC_BUTTON1, OnButtonClicked) 
END_MESSAGE_MAP()
  • 本質:靜態數組存儲 <消息ID, 處理函數指針> 映射。
  • AfxWndProc 通過 CWnd::WindowProc 查表分發,最終調用成員函數。
  • 優點:類型安全、面向對象、自動處理 this 指針傳遞。

六、自定義消息最佳實踐

  1. 線程內:#define WM_MYMSG (WM_USER + 100),PostMessage(hwnd, WM_MYMSG, wp, lp)。
  2. 跨進程/系統全局唯一:UINT WM_MYGLOBAL = RegisterWindowMessage(_T("MyApp_Unique_Message_Name"));。
  3. 參數傳遞:wParam/lParam 傳指針時,確保目標窗口線程可訪問該內存(共享內存/序列化/全局堆)。

總結

Windows 消息機制是「事件驅動」架構的基石:硬件中斷 → 系統隊列 → 線程隊列 → 消息循環 → 分發 → 窗口過程 → DefWindowProc。理解排隊/非排隊差異、消息循環四大函數職責、MFC 消息映射實現原理,是 Windows 開發調試疑難雜症(繞不開的卡死、重繪異常、跨線程調用)的核心鑰匙。本文整理自 51CTO 博客「理解Windows消息機制」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
類型示例特點
排隊消息WM_PAINT, WM_TIMER, WM_CHAR, WM_MOUSEMOVE經線程隊列,GetMessage 取出,可合併(多次 WM_PAINT 合併為一次)
非排隊消息WM_ACTIVATE, WM_SETFOCUS, WM_WINDOWPOSCHANGING直接發送到窗口過程(SendMessage),繞過隊列,同步阻塞直到處理完成