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

Win32 開發入門(2):完整開發流程與常見陷阱

     編輯:關於C++

Win32 應用程式六大步驟

  1. WinMain 入口點
  2. 設計與註冊視窗類別
  3. 建立與顯示視窗
  4. 更新視窗 (可選)
  5. 訊息迴圈
  6. 訊息回應

1. WinMain 入口點


int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,      // 目前應用程式實例控制代碼
    _In_ HINSTANCE hPrevInstance,  // 前一個實例 (Win32 恆為 NULL)
    _In_ LPSTR lpCmdLine,          // 命令列參數 (ANSI 字串)
    _In_ int nCmdShow              // 主視窗顯示方式 (SW_SHOW 等)
);
  • CALLBACK = __stdcall 呼叫慣例 (Pascal 風格,參數由呼叫者清除堆疊)
  • 專案屬性 → C/C++ → 進階 → 呼叫慣例預設為 __cdecl,WinAPI 需 __stdcall
  • 回傳 0 表正常結束,非 0 表異常

新建 Win32 專案

專案精靈設定

呼叫慣例設定

nCmdShow 顯示方式常數

捷徑屬性執行方式

2. 視窗程序與前置宣告

C++ 編譯器由上而下解析,WindowProc 實作在 WinMain 之後,必須前置宣告:


LRESULT CALLBACK WindowProc(
    _In_ HWND hwnd, _In_ UINT uMsg,
    _In_ WPARAM wParam, _In_ LPARAM lParam
);
  • 函數名稱可自訂 (如 MyProc),但簽章必須一致
  • lpfnWndProc 傳遞函數指標,系統透過此指標呼叫回呼函數
  • 未處理的訊息交給 DefWindowProc 預設處理

3. 設計與註冊視窗類別 (WNDCLASS)


WNDCLASS wc = { }; // 大括號初始化,所有成員歸零
wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // 背景畫刷
wc.lpfnWndProc = WindowProc;             // 視窗程序
wc.lpszClassName = L"My Class";         // 類別名稱
wc.hInstance = hInstance;                // 實例控制代碼
// 註冊
RegisterClass(&wc);

關鍵陷阱:結構體必須完整初始化

MSDN 文件註明:"You must fill the structure with the appropriate class attributes before passing it to the function."

未初始化的成員含隨機值會導致 RegisterClass 失敗,視窗建立失敗 (hwnd = NULL)。

三種初始化寫法


// 1. 逐一賦值 (繁瑣)
wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hCursor = ...; ...

// 2. 指定大小 (C 風格)
WNDCLASS wc = { sizeof(WNDCLASS) };

// 3. 空大括號 (C++11 推薦,最簡潔)
WNDCLASS wc = { };

正常執行視窗

4. 建立與顯示視窗


HWND hwnd = CreateWindow(
    L"My Class",           // 類別名
    L"我的應用程式",       // 標題
    WS_OVERLAPPEDWINDOW,   // 視窗樣式
    38, 20, 480, 250,      // x, y, 寬, 高
    NULL, NULL,            // 父視窗、選單
    hInstance, NULL        // 實例、額外參數
);
if (hwnd == NULL) return 0; // 建立失敗檢查

ShowWindow(hwnd, SW_SHOW);  // 顯示
UpdateWindow(hwnd);         // 立即傳送 WM_PAINT (可選)

5. 訊息迴圈

Windows 為訊息驅動架構,需死循環取出並分派訊息:


MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg); // 鍵盤訊息轉換 (WM_KEYDOWN → WM_CHAR)
    DispatchMessage(&msg);  // 分派至 WindowProc
}
  • GetMessage 從佇列取出訊息填入 MSG 結構,遇 WM_QUIT 回傳 0 跳出迴圈
  • TranslateMessage 將虛擬鍵碼轉為字元訊息
  • DispatchMessage 依 MSG.hwnd 找到視窗程序並呼叫

6. 訊息回應與程式結束

視窗關閉觸發 WM_DESTROY,呼叫 PostQuitMessage(0) 貼上 WM_QUIT,使 GetMessage 回傳 0 結束迴圈:


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0); return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

完整程式碼清單


#include <Windows.h>

LRESULT CALLBACK WindowProc(
    _In_ HWND hwnd, _In_ UINT uMsg,
    _In_ WPARAM wParam, _In_ LPARAM lParam
);

int CALLBACK WinMain(
    _In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine, _In_ int nCmdShow
) {
    WCHAR* cls_Name = L"My Class";
    WNDCLASS wc = { };
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpfnWndProc = WindowProc;
    wc.lpszClassName = cls_Name;
    wc.hInstance = hInstance;
    RegisterClass(&wc);
    
    HWND hwnd = CreateWindow(
        cls_Name, L"我的應用程式", WS_OVERLAPPEDWINDOW,
        38, 20, 480, 250, NULL, NULL, hInstance, NULL
    );
    if (hwnd == NULL) return 0;
    
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);
    
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

LRESULT CALLBACK WindowProc(
    _In_ HWND hwnd, _In_ UINT uMsg,
    _In_ WPARAM wParam, _In_ LPARAM lParam
) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0); return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

重點整理

  • Win32 程式六步驟:WinMain → 視窗類別 → 建立視窗 → 顯示/更新 → 訊息迴圈 → 訊息處理
  • WNDCLASS **必須完整初始化**,推薦 WNDCLASS wc = { };
  • RegisterClass 失敗會導致 CreateWindow 傳回 NULL
  • 訊息迴圈核心:GetMessage → TranslateMessage → DispatchMessage
  • WM_DESTROY → PostQuitMessage → WM_QUIT → 迴圈結束 → 程式退出
  • DefWindowProc 處理未關心的訊息,保留系統預設行為
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved