每條消息是一個 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);
}
}
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 並調用。| 類型 | 示例 | 特點 |
|---|---|---|
| 排隊消息 | WM_PAINT, WM_TIMER, WM_CHAR, WM_MOUSEMOVE | 經線程隊列,GetMessage 取出,可合併(多次 WM_PAINT 合併為一次) |
| 非排隊消息 | WM_ACTIVATE, WM_SETFOCUS, WM_WINDOWPOSCHANGING | 直接發送到窗口過程(SendMessage),繞過隊列,同步阻塞直到處理完成 |