Windows 程式具有相對固定結構,開發者只需填寫系統預留的核心部分:視窗類別定義、視窗建立、訊息函式撰寫、訊息迴路。
Windows 程式是事件驅動。每個視窗有訊息處理函式,系統處理大部分例行維護。開發者將處理函式與視窗關聯,有訊息產生時自動調用。通常只處理感興趣的訊息,其餘交由系統預設處理函式 DefWindowProc。
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0); // 發送退出訊息結束訊息迴路
return 0;
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
建立視窗獲得系統回傳控制代碼 (HWND),後續操作皆針對控制代碼。
WNDCLASS 結構,核心是關聯訊息處理函式,其他屬性含功能表、圖示等。系統預定義類別(按鈕等控制項)無需自行註冊,直接使用類別名稱。CreateWindow,系統據此調用類別中指定的處理函式。系統將訊息放入程式「訊息佇列」,程式依序取出、分派至對應視窗。建立視窗後進入迴路,直到取得退出訊息 (WM_QUIT) 結束。
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg); // 轉換鍵盤訊息 (WM_KEYDOWN → WM_CHAR)
DispatchMessage(&msg); // 分派至視窗處理函式
}
#include
// 1. 訊息處理函式
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
// 2. 應用程式進入點
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
// 註冊視窗類別
static TCHAR szAppName[] = TEXT("HelloWin");
WNDCLASS wndclass = {0};
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("註冊失敗!"), szAppName, MB_ICONERROR);
return 0;
}
// 建立視窗
HWND hwnd = CreateWindow(szAppName, TEXT("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
// 訊息迴路
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
| 欄位 | 用途 | 常用值 |
|---|---|---|
| style | 類別樣式 | CS_HREDRAW \| CS_VREDRAW (水平/垂直重繪) |
| lpfnWndProc | 訊息處理函式指標 | WndProc |
| cbClsExtra / cbWndExtra | 額外記憶體位元組 | 通常 0 |
| hInstance | 應用程式實例控制代碼 | WinMain 參數 hInstance |
| hIcon | 類別圖示 | LoadIcon(NULL, IDI_APPLICATION) |
| hCursor | 類別游標 | LoadCursor(NULL, IDC_ARROW) |
| hbrBackground | 背景筆刷 | GetStockObject(WHITE_BRUSH) |
| lpszMenuName | 功能表資源名稱 | NULL 或 MAKEINTRESOURCE(IDR_MENU) |
| lpszClassName | 類別名稱字串 | 自訂唯一名稱 |
| 參數 | 說明 | 常用值 |
|---|---|---|
| lpClassName | 視窗類別名稱 | 註冊時的 lpszClassName |
| lpWindowName | 視窗標題列文字 | TEXT("標題") |
| dwStyle | 視窗樣式 | WS_OVERLAPPEDWINDOW (標準主視窗) |
| x, y | 初始位置 | CW_USEDEFAULT (系統決定) |
| nWidth, nHeight | 初始大小 | CW_USEDEFAULT |
| hWndParent | 父視窗控制代碼 | NULL (主視窗無父視窗) |
| hMenu | 功能表/子視窗 ID | NULL 或 (HMENU)ID |
| hInstance | 實例控制代碼 | WinMain 參數 |
| lpParam | 建立參數傳給 WM_CREATE | NULL 或自訂結構指標 |
typedef struct tagMSG {
HWND hwnd; // 接收視窗
UINT message; // 訊息識別碼
WPARAM wParam; // 32 位元參數 1
LPARAM lParam; // 32 位元參數 2
DWORD time; // 訊息建立時間
POINT pt; // 滑鼠螢幕座標
} MSG;
WM_ACTIVATE、WM_SETFOCUS、API 呼叫產生的訊息| 函式 | 行為 | 回傳時機 |
|---|---|---|
| SendMessage | 同步發送,直接呼叫視窗程式 | 處理完成後回傳 |
| PostMessage | 非同步佇列,放入訊息佇列 | 放入佇列即回傳 |
switch (message)
{
case WM_CREATE:
// 初始化、建立子視窗、配置資源
return 0;
case WM_PAINT:
// 繪圖邏輯
return 0;
case WM_COMMAND:
// 功能表/控制項命令
return 0;
case WM_SIZE:
// 視窗大小變更,重新配置版面
return 0;
case WM_TIMER:
// 計時器觸發
return 0;
case WM_DESTROY:
// 清理資源、發送退出訊息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
TCHAR/TEXT() 宏支援雙版本dpiAware 或 PerMonitorV2GetLastError