什麼是訊息?
訊息系統是 Win32 程式運行的動力源泉。一個訊息是系統定義的 32 位元值,唯一定義一個事件,通知應用程式某事發生:滑鼠點擊、視窗大小變更、鍵盤按鍵等。訊息以記錄形式傳遞,包含類型與額外資訊 (如滑鼠座標)。記錄類型為 MSG:
typedef struct tagMSG
{
HWND hwnd; // 接收視窗控制代碼
UINT message; // 訊息常數識別碼 (訊息號)
WPARAM wParam; // 32 位元附加資訊,具體含義依賴訊息值
LPARAM lParam; // 32 位元附加資訊,具體含義依賴訊息值
DWORD time; // 訊息建立時間
POINT pt; // 訊息建立時滑鼠/游標螢幕座標
} MSG;
訊息來源
- 系統產生:輸入事件 (按鍵、滑鼠、點擊控制項)、應用程式帶來的系統變化 (字體變更、視窗大小調整)
- 應用程式產生:讓視窗執行任務、與其他應用程式視窗通訊
訊息結構欄位深度解析
| 欄位 | 類型 | 詳細說明 |
| hwnd | HWND | 32 位視窗控制代碼。Win32 維護多數可視物件控制代碼 (視窗、對話方塊、按鈕、編輯框等) |
| message | UINT | 區別其他訊息的常數值。預定義常數或自訂常數。視窗程序用此決定如何處理。如 WM_PAINT 告知客戶區需重繪。前綴指明處理視窗類型 |
| wParam | WPARAM | 通常為相關常數值,也可能是視窗/控制項控制代碼 |
| lParam | LPARAM | 通常為指向記憶體資料的指標。WPARAM/LPARAM/Pointer 皆 32 位,可互轉 |
| time | DWORD | 訊息建立時間 (毫秒,系統啟動後) |
| pt | POINT | 滑鼠/游標螢幕座標 |
訊息識別碼數值範圍與分類
| 範圍 | 用途 | 說明 |
| 0x0000 - 0x03FF (WM_USER-1) | 系統保留 | 系統定義訊息,應用程式不可使用 |
| 0x0400 (WM_USER) - 0x7FFF | 應用程式私有 | 應用程式內部使用,視窗類別私有 |
| 0x8000 (WM_APP) - 0xBFFF | 應用程式全域 | 跨視窗類別的應用程式訊息 |
| 0xC000 - 0xFFFF | 跨應用程式通訊 | RegisterWindowMessage 產生,系統保證唯一 |
關鍵訊息值對照表
| 訊息 | 值 | 說明 |
| WM_NULL | 0x0000 | 空訊息 |
| 0x0001 - 0x0087 | - | 主要視窗訊息 |
| 0x00A0 - 0x00A9 | - | 非客戶區訊息 |
| 0x0100 - 0x0108 | - | 鍵盤訊息 |
| 0x0111 - 0x0126 | - | 功能表訊息 |
| 0x0132 - 0x0138 | - | 色彩控制訊息 |
| 0x0200 - 0x020A | - | 滑鼠訊息 |
| 0x0211 - 0x0213 | - | 功能表迴路訊息 |
| 0x0220 - 0x0230 | - | 多文件訊息 (MDI) |
| 0x03E0 - 0x03E8 | - | DDE 訊息 |
| WM_USER | 0x0400 | 應用程式私有訊息起始 |
| WM_APP | 0x8000 | 應用程式全域訊息起始 |
訊息三大分類
| 類別 | 定義 | 處理者範圍 | 典型例子 |
| 視窗訊息 | 作業系統與控制其他視窗的視窗使用 | 視窗類別 (CWnd 衍生) | CreateWindow、DestroyWindow、MoveWindow、滑鼠點擊 |
| 命令訊息 | 特殊視窗訊息,處理視窗間使用者請求 | 視窗類別、文件類別、文件樣板類別、應用程式類別 | 按下按鈕 → 發送命令訊息給主視窗 |
| 控制項通知訊息 | 子控制項發生事件需通知父視窗 | 視窗類別 (CWnd 衍生) | 點擊/雙擊控制項、選取文字、操作捲軸 |
命令訊息處理者範圍最廣,不限於視窗類別。控制項通知訊息類似命令訊息 (從控制項發送至父視窗),但目的在讓父視窗改變控制項 (載入/顯示資料),而非處理使用者命令。按鈕點擊既可視為命令訊息也可視為通知訊息;滑鼠點擊可由主視窗直接處理或交給控制項。
常見控制項通知訊息完整對照
按鈕控制項 (Button)
| 通知代碼 | 觸發條件 |
| BN_CLICKED | 使用者單擊按鈕 |
| BN_DISABLE | 按鈕被停用 |
| BN_DOUBLECLICKED | 使用者雙擊按鈕 |
| BN_HILITE | 使用者高亮按鈕 |
| BN_PAINT | 按鈕應重繪 |
| BN_UNHILITE | 高亮應移除 |
下拉式方塊 (ComboBox)
| 通知代碼 | 觸發條件 |
| CBN_CLOSEUP | 清單方塊關閉 |
| CBN_DBLCLK | 雙擊字串 |
| CBN_DROPDOWN | 清單方塊展開 |
| CBN_EDITCHANGE | 編輯框文字變更 |
| CBN_EDITUPDATE | 編輯框文字即將更新 |
| CBN_ERRSPACE | 記憶體不足 |
| CBN_KILLFOCUS | 失去輸入焦點 |
| CBN_SELCHANGE | 選取項目變更 |
| CBN_SELENDCANCEL | 選取應取消 |
| CBN_SELENDOK | 選取合法 |
| CBN_SETFOCUS | 獲得輸入焦點 |
編輯框 (Edit)
| 通知代碼 | 觸發條件 |
| EN_CHANGE | 文字已更新 |
| EN_ERRSPACE | 記憶體不足 |
| EN_HSCROLL | 點擊水平捲軸 |
| EN_KILLFOCUS | 正在失去焦點 |
| EN_MAXTEXT | 插入內容被截斷 |
| EN_SETFOCUS | 獲得輸入焦點 |
| EN_UPDATE | 文字即將更新 |
| EN_VSCROLL | 點擊垂直捲軸 |
清單方塊 (ListBox)
| 通知代碼 | 觸發條件 |
| LBN_DBLCLK | 雙擊項目 |
| LBN_ERRSPACE | 記憶體不足 |
| LBN_KILLFOCUS | 正在失去焦點 |
| LBN_SELCANCEL | 選取被取消 |
| LBN_SELCHANGE | 選取其他項目 |
| LBN_SETFOCUS | 獲得輸入焦點 |
自訂訊息最佳實務
- 視窗類別私有:
#define WM_MYMSG (WM_USER + 1)
- 應用程式全域:
#define WM_MYAPPMSG (WM_APP + 1)
- 跨程式通訊:
UINT WM_MYGLOBAL = RegisterWindowMessage(TEXT("MyUniqueMessageName"));
- 避免衝突:WM_USER 範圍僅在同一視窗類別內有效,不同類別可重用相同值
下一章預告
下回將深入探討:佇列/非佇列訊息機制、SendMessage/PostMessage 發送與佇列差異、GetMessage/PeekMessage 接收處理、標準訊息泵運作細節、視窗程序架構與 WindowsX.h 訊息分發器技術。