首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows API 入門 (二):視窗程序核心架構與訊息分派實戰

     編輯:VC 教學

什麼是視窗程序?

視窗程序是應用程式處理接收訊息的核心函數,包含對所有可能接收訊息的處理分支。本質上是一個巨大的 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) (通知碼)。
  • ❌ 在視窗程序中執行阻塞操作 (Sleep、資料庫、網路) → UI 凍結。

進階:子類別化攔截既有視窗


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 程式的「大腦」,掌握其架構即掌握了視窗行為的終極控制權。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved