視窗程序是應用程式處理接收訊息的核心函數,包含對所有可能接收訊息的處理分支。本質上是一個巨大的 switch(message) 語句集合,每個 case 對應一種訊息類型。
LRESULT CALLBACK WndProc(
HWND hwnd, // 視窗句柄
UINT message, // 訊息識別碼
WPARAM wParam, // 參數 1
LPARAM lParam // 參數 2
)
{
switch (message) {
case WM_CREATE:
// 初始化:建立子視窗、配置資源、設定定時器
return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// 繪製邏輯...
EndPaint(hwnd, &ps);
return 0;
}
case WM_COMMAND:
// 選單/控制項通知
switch (LOWORD(wParam)) {
case IDM_FILE_EXIT:
DestroyWindow(hwnd);
break;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0); // 發送 WM_QUIT 結束訊息迴圈
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam); // 關鍵:預設處理
}
return 0;
}
| 原則 | 說明 |
|---|---|
| 必須處理 WM_DESTROY | 否則程式無法正常退出 (訊息迴圈不會收到 WM_QUIT) |
| default 必須呼叫 DefWindowProc | 系統預設行為:視窗移動、最小化、系統選單、預設繪製等 |
| 返回值語意 | 0 = 已處理;非零 = 特定含義 (如 WM_CTLCOLOR 返回刷子句柄) |
| CALLBACK = __stdcall | 確保參數堆疊清理正確,防止呼叫慣例不匹配崩潰 |
GetMessage → DispatchMessage
│
▼
目標視窗程序
│
├─ WM_CREATE → 初始化
├─ WM_PAINT → 繪製
├─ WM_COMMAND → 選單/按鈕/編輯框通知
├─ WM_SIZE → 佈局調整
├─ WM_TIMER → 定時任務
├─ WM_KEYDOWN → 鍵盤輸入
├─ WM_MOUSEMOVE → 滑鼠追蹤
├─ WM_DESTROY → 清理 + PostQuitMessage
└─ 其他 → DefWindowProc
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
// 1. 視窗類別註冊
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("MinimalWndClass");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClass(&wc);
// 2. 建立視窗
HWND hwnd = CreateWindow(
wc.lpszClassName, TEXT("Minimal API Window"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
640, 480, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 3. 訊息迴圈
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
DefWindowProc → 視窗無法移動、關閉、最小化。WM_PAINT 中未呼叫 BeginPaint/EndPaint → 重繪迴圈、CPU 100%。WM_COMMAND 未區分 LOWORD(wParam) (控制項 ID) 與 HIWORD(wParam) (通知碼)。
WNDPROC g_OldProc = NULL;
LRESULT CALLBACK NewProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (msg == WM_LBUTTONDOWN) {
// 自訂左鍵邏輯
return 0;
}
return CallWindowProc(g_OldProc, hwnd, msg, wp, lp);
}
// 掛鉤
g_OldProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewProc);
// 卸載
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)g_OldProc);

視窗程序是 Windows 程式的「大腦」,掌握其架構即掌握了視窗行為的終極控制權。