回顧純 SDK 寫法,建立視窗類別、註冊、建立視窗、訊息迴圈:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY: PostQuitMessage(0); break;
case WM_PAINT: {
PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps);
DrawText(hdc, _T("Hello, SDK!"), -1, &ps.rcPaint, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
EndPaint(hWnd, &ps);
} break;
default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
BOOL InitApp(HINSTANCE hInst) {
WNDCLASS wc = { CS_HREDRAW|CS_VREDRAW, WndProc, 0,0, hInst,
LoadIcon(NULL,IDI_APPLICATION), LoadCursor(NULL,IDC_ARROW),
(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, _T("HelloSDK") };
return RegisterClass(&wc);
}
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR, int nShow) {
InitApp(hInst);
HWND hWnd = CreateWindow(_T("HelloSDK"), _T("Hello SDK"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
ShowWindow(hWnd, nShow); UpdateWindow(hWnd);
MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam;
}
SDK 寫法冗長且重複。ATL 以 模板 + 多重繼承 將「屬性(視窗類別樣式)」、「方法(視窗操作 API)」、「事件(訊息響應)」分離組合,實現「活版印刷」式封裝,大幅減少樣板代碼。
詳細剖析 `CWindowImpl`、`CWindow`、`CWinTraits`、`CMessageMap` 四大核心模板類別,展示如何用最少代碼建立功能完整的 ATL 視窗。