WNDCLASS/WNDCLASSEX)RegisterClass)CreateWindow/CreateWindowEx)ShowWindow, UpdateWindow)
HICON LoadIcon(
HINSTANCE hInstance, // 模組句柄,NULL = 系統預設
LPCTSTR lpIconName // 資源名或 MAKEINTRESOURCE(IDI_*)
);
IDI_APPLICATION, IDI_HAND, IDI_QUESTION, IDI_EXCLAMATION, IDI_ASTERISK, IDI_WINLOGO。
HCURSOR LoadCursor(
HINSTANCE hInstance, // NULL = 系統預設
LPCTSTR lpCursorName // IDC_ARROW, IDC_IBEAM, IDC_WAIT, IDC_CROSS, IDC_SIZEALL...
);
HGDIOBJ GetStockObject(int fnObject);
// 常用:WHITE_BRUSH, BLACK_BRUSH, GRAY_BRUSH, DKGRAY_BRUSH, NULL_BRUSH,
// SYSTEM_FONT, DEFAULT_GUI_FONT, SYSTEM_FIXED_FONT
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // 重繪風格 + 雙擊支援
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); // 或 NULL
wc.lpszClassName = TEXT("MyWindowClass");
if (!RegisterClass(&wc)) {
MessageBox(NULL, TEXT("註冊失敗"), TEXT("錯誤"), MB_ICONERROR);
return 0;
}
// 成功返回類別原子 (ATOM),失敗返回 0
HWND CreateWindow(
LPCTSTR lpClassName, // 註冊類別名
LPCTSTR lpWindowName, // 視窗標題
DWORD dwStyle, // 視窗風格 (WS_*)
int x, int y, // 左上角座標 (CW_USEDEFAULT = 系統決定)
int nWidth, int nHeight, // 寬高
HWND hWndParent, // 父視窗句柄 (NULL = 無)
HMENU hMenu, // 選單句柄 / 子視窗 ID
HINSTANCE hInstance, // 模組句柄
LPVOID lpParam // 傳遞給 WM_CREATE 的 lpCreateParams
);
| 風格 | 值 | 效果 |
|---|---|---|
| WS_OVERLAPPED | 0x00000000 | 重疊視窗 (有標題列、邊框) |
| WS_POPUP | 0x80000000 | 彈出視窗 (無標題列、邊框) |
| WS_CHILD | 0x40000000 | 子視窗 (必須有父視窗) |
| WS_MINIMIZE | 0x20000000 | 初始最小化 |
| WS_VISIBLE | 0x10000000 | 初始可見 |
| WS_DISABLED | 0x08000000 | 初始停用 |
| WS_CLIPSIBLINGS | 0x04000000 | 裁剪同層兄弟視窗 |
| WS_CLIPCHILDREN | 0x02000000 | 裁剪子視窗區域 |
| WS_MAXIMIZE | 0x01000000 | 初始最大化 |
| WS_CAPTION | 0x00C00000 | 標題列 (包含 WS_BORDER | WS_DLGFRAME) |
| WS_BORDER | 0x00800000 | 細邊框 |
| WS_DLGFRAME | 0x00400000 | 對話框邊框 (無標題) |
| WS_VSCROLL | 0x00200000 | 垂直捲軸 |
| WS_HSCROLL | 0x00100000 | 水平捲軸 |
| WS_SYSMENU | 0x00080000 | 系統選單 (關閉/移動/大小/最小化/最大化) |
| WS_THICKFRAME | 0x00040000 | 可調整大小邊框 (含 WS_BORDER) |
| WS_GROUP | 0x00020000 | 控制項群組首項 (Tab 導航) |
| WS_TABSTOP | 0x00010000 | 可接收焦點 (Tab 鍵) |
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOXWS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENUWS_CHILDWINDOW = WS_CHILD
// 同時擁有垂直與水平捲軸的彈出視窗
DWORD style = WS_POPUP | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU;
// ShowWindow 顯示狀態控制
BOOL ShowWindow(HWND hWnd, int nCmdShow);
// nCmdShow 常用值:
// SW_HIDE (0), SW_SHOWNORMAL (1), SW_SHOWMINIMIZED (2), SW_SHOWMAXIMIZED (3),
// SW_SHOWNOACTIVATE (4), SW_RESTORE (9)
// UpdateWindow 強制發送 WM_PAINT
BOOL UpdateWindow(HWND hWnd);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nShow)
{
// 1. 類別定義
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.lpszClassName = TEXT("DemoClass");
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClass(&wc);
// 2. 建立視窗
HWND hwnd = CreateWindow(
TEXT("DemoClass"), TEXT("API Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, hInst, NULL);
// 3. 顯示
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd);
// 4. 訊息迴圈
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
| 錯誤 | 原因 | 修正 |
|---|---|---|
| RegisterClass 失敗 | 類別名重複、結構體未歸零 | 使用唯一名稱、WNDCLASS wc = {0}; |
| CreateWindow 返回 NULL | 類別未註冊、風格衝突 (如 WS_CHILD 無父視窗) | 檢查 GetLastError(),確認父視窗有效 |
| 視窗不顯示 | 未呼叫 ShowWindow/UpdateWindow | 務必呼叫兩者 |
| 背景不重繪 | hbrBackground 為 NULL 或未處理 WM_ERASEBKGND | 設定股票刷子或自行處理 WM_ERASEBKGND |

這四個步驟構成了所有 Windows GUI 程式的基石,熟練掌握每個參數含義,是進階開發的前提。