一、核心概念理解

1.1 Windows 程序的工作原理

Windows 程序基于事件驱动模型

  • 用户操作(点击、输入)产生消息(Message)
  • Windows 将消息放入消息队列
  • 程序从队列取出消息并处理
  • 这个循环称为消息循环(Message Loop)

1.2 四个关键步骤

  1. 注册窗口类:告诉Windows你的窗口长什么样
  2. 创建窗口:真正生成窗口实例
  3. 消息循环:不断接收和分发消息
  4. 窗口过程:处理各种消息的函数

二、关键 API 函数详解

2.1 窗口类相关

WNDCLASSEX 结构体

定义窗口的基本属性:

WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);           // 结构体大小
wc.lpfnWndProc = WindowProc;              // 窗口过程函数指针
wc.hInstance = hInstance;                 // 应用程序实例句柄
wc.lpszClassName = L"MyWindowClass";      // 窗口类名(唯一标识)
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 鼠标光标
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // 背景颜色
RegisterClassEx()

向系统注册窗口类:

if (!RegisterClassEx(&wc)) {
    MessageBox(NULL, L"窗口注册失败!", L"错误", MB_ICONERROR);
    return 0;
}

2.2 窗口创建

CreateWindowEx()

创建窗口实例:

HWND hwnd = CreateWindowEx(
    0,                      // 扩展样式
    L"MyWindowClass",       // 窗口类名(必须与注册时一致)
    L"我的第一个窗口",       // 窗口标题
    WS_OVERLAPPEDWINDOW,    // 窗口样式(标准窗口)
    CW_USEDEFAULT,          // X 坐标(默认)
    CW_USEDEFAULT,          // Y 坐标(默认)
    800,                    // 宽度
    600,                    // 高度
    NULL,                   // 父窗口句柄
    NULL,                   // 菜单句柄
    hInstance,              // 应用实例
    NULL                    // 附加参数
);

常用窗口样式:

  • WS_OVERLAPPEDWINDOW:标准窗口(可调整大小)
  • WS_POPUP:无边框窗口
  • WS_VISIBLE:创建后立即显示

2.3 消息循环

GetMessage() / TranslateMessage() / DispatchMessage()
MSG msg = {0};
// GetMessage() 从队列获取消息,返回0时退出循环
while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);  // 转换键盘消息
    DispatchMessage(&msg);   // 分发到窗口过程函数
}

2.4 窗口过程函数

处理消息的核心函数:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:  // 窗口销毁消息
            PostQuitMessage(0);  // 发送退出消息
            return 0;
        
        case WM_PAINT: {  // 窗口重绘消息
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            // 在这里绘制内容
            TextOut(hdc, 50, 50, L"Hello Windows!", 14);
            EndPaint(hwnd, &ps);
            return 0;
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);  // 默认处理
}

常用消息:

  • WM_CREATE:窗口创建时
  • WM_DESTROY:窗口销毁时
  • WM_PAINT:需要重绘时
  • WM_LBUTTONDOWN:鼠标左键按下
  • WM_KEYDOWN:键盘按键按下

三、完整示例代码

#include <windows.h>

// 窗口过程函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// 主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                   LPSTR lpCmdLine, int nCmdShow) {
    
    // ========== 步骤1:注册窗口类 ==========
    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;  // 窗口样式
    wc.lpfnWndProc = WindowProc;         // 指定窗口过程函数
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = L"MyFirstWindow";
    
    if (!RegisterClassEx(&wc)) {
        MessageBox(NULL, L"窗口注册失败!", L"错误", MB_ICONERROR);
        return 0;
    }
    
    // ========== 步骤2:创建窗口 ==========
    HWND hwnd = CreateWindowEx(
        0,
        L"MyFirstWindow",        // 窗口类名
        L"C++ Windows 入门示例", // 标题栏文字
        WS_OVERLAPPEDWINDOW,     // 标准窗口样式
        CW_USEDEFAULT, CW_USEDEFAULT,  // 位置
        800, 600,                // 大小
        NULL, NULL,
        hInstance,
        NULL
    );
    
    if (hwnd == NULL) {
        MessageBox(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR);
        return 0;
    }
    
    // 显示并更新窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    
    // ========== 步骤3:消息循环 ==========
    MSG msg = {0};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    return (int)msg.wParam;
}

// ========== 步骤4:窗口过程函数 ==========
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            // 用户关闭窗口时,发送退出消息
            PostQuitMessage(0);
            return 0;
        
        case WM_PAINT: {
            // 窗口需要重绘时
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            
            // 设置文字颜色和背景
            SetTextColor(hdc, RGB(0, 0, 255));
            SetBkMode(hdc, TRANSPARENT);
            
            // 显示文字
            TextOut(hdc, 100, 100, L"欢迎学习 Windows 编程!", 13);
            TextOut(hdc, 100, 150, L"这是你的第一个窗口程序", 12);
            
            EndPaint(hwnd, &ps);
            return 0;
        }
        
        case WM_LBUTTONDOWN: {
            // 鼠标左键点击时显示提示
            MessageBox(hwnd, L"你点击了窗口!", L"提示", MB_OK | MB_ICONINFORMATION);
            return 0;
        }
        
        case WM_KEYDOWN: {
            // 按下ESC键时关闭窗口
            if (wParam == VK_ESCAPE) {
                DestroyWindow(hwnd);
            }
            return 0;
        }
    }
    
    // 其他消息交给默认处理函数
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

四、编译运行

Visual Studio

  1. 创建新的 Windows Desktop Application 项目
  2. 将代码替换到 main.cpp
  3. F5 运行

命令行编译

cl /EHsc your_file.cpp user32.lib gdi32.lib

五、学习路线建议

初级阶段

  1. 理解消息循环机制
  2. 掌握基本控件(按钮、文本框)
  3. 学习 GDI 绘图基础

进阶方向

  • Win32 API:深入学习更多API
  • MFC:微软提供的C++框架(封装了API)
  • WinUI / WPF:现代化的界面框架
  • Qt:跨平台GUI框架

六、常见问题

Q:为什么函数名前有L?
A:L"文字" 表示宽字符(Unicode),Windows API 推荐使用。

Q:句柄(HWND)是什么?
A:句柄是 Windows 对象的唯一标识符,类似于"身份证号"。

Q:为什么要用消息循环?
A:Windows 是多任务系统,消息机制让程序能响应用户操作而不阻塞系统。


七、调试技巧

// 输出调试信息到调试器
OutputDebugString(L"程序运行到这里\n");

// 显示变量值
wchar_t buffer[100];
wsprintf(buffer, L"变量值:%d", myValue);
MessageBox(NULL, buffer, L"调试", MB_OK);

学习建议: 先运行示例代码,然后尝试修改窗口标题、大小、颜色等参数,观察效果。逐步理解每个API的作用后,再添加新功能。编程是实践的过程,多写多试才能真正掌握!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐