C语言Windows编程如何快速入门?

99ANYc3cd6
预计阅读时长 25 分钟
位置: 首页 C语言 正文

核心概念:Windows API 是什么?

当你用 C 语言在 Windows 上写程序时,你实际上是在调用由 Windows 操作系统本身提供的一系列函数、宏和数据结构,这个庞大的函数集合就是 Windows API

c语言 windows编程
(图片来源网络,侵删)
  • 作用:它就像是操作系统和你的应用程序之间的“翻译官”或“中间人”,你的程序告诉 Windows:“我想要创建一个窗口”、“我想要在窗口上画一条线”、“当用户点击鼠标时请通知我”,Windows API 就负责把这些请求翻译成系统能理解的指令,并返回结果。
  • 特点
    • 原生:这是 Windows 最底层的接口,功能最强大,也最复杂。
    • C 语言风格:Windows API 主要用 C 语言编写,其函数命名、参数传递等风格非常符合 C 语言的规范。
    • 头文件和库:使用 Windows API 需要包含特定的头文件(如 windows.h),并链接到对应的库文件(如 kernel32.lib, user32.lib)。

第一个 Windows 程序:一个“空”窗口

一个最基础的 Windows GUI 程序,通常需要以下几个核心部分:

  1. 程序入口点:不同于控制台程序的 main(),GUI 程序的入口是 WinMain()
  2. 窗口注册:告诉 Windows 你要创建的窗口是什么样的(类名、图标、窗口过程函数等)。
  3. 窗口创建:根据注册的窗口类,实际创建一个窗口句柄。
  4. 消息循环:一个无限循环,用于获取和分发来自用户(键盘、鼠标)或系统的事件消息。
  5. 窗口过程:一个回调函数,专门处理窗口收到的各种消息(如绘制、点击、关闭等)。

详细步骤与代码解析

下面我们一步步来构建一个经典的 Windows 窗口程序。

包含头文件和链接库

#include <windows.h> // 这是所有 Windows API 的核心头文件
// 省略省略...

编译时,你需要链接到 Windows 的核心库,在 Visual Studio 中通常会自动处理,如果你用命令行编译(如 MinGW 的 GCC),需要加上: gcc your_file.c -o your_program.exe -mwindows -mwindows 参数会自动链接上所需的 GUI 库。

程序入口点:WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // ... 程序的主要逻辑将在这里 ...
    return 0;
}
  • HINSTANCE hInstance:当前实例的句柄,可以理解为程序的“身份证号”。
  • HINSTANCE hPrevInstance:在 32/64 位 Windows 中,这个参数总是 NULL
  • LPSTR lpCmdLine:命令行参数字符串。
  • int nCmdShow:指定窗口如何显示(如正常显示、最大化、最小化)。

窗口过程函数:WndProc

这是一个回调函数,Windows 会在特定事件发生时调用它。

c语言 windows编程
(图片来源网络,侵删)
// 窗口过程函数的声明
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 函数实现
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_DESTROY: // 当窗口被销毁时(例如点击关闭按钮)
        PostQuitMessage(0); // 向消息队列发送一个 WM_QUIT 消息,结束消息循环
        return 0;
    case WM_PAINT: // 当窗口需要重绘时(例如窗口被遮挡后又显示)
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps); // 开始绘制
            // 在这里可以添加绘制代码,比如画文字
            TextOut(hdc, 50, 50, L"Hello, Windows API!", 19);
            EndPaint(hwnd, &ps); // 结束绘制
        }
        return 0;
    }
    // 对于我们没有处理的消息,交给系统默认处理
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
  • HWND hwnd:接收消息的窗口句柄。
  • UINT uMsg:消息本身(如 WM_DESTROY, WM_PAINT)。
  • WPARAM wParam / LPARAM lParam:消息的附加参数。

注册窗口类

在创建窗口之前,必须先“注册”一个窗口类,告诉 Windows 这个窗口的“模板”是什么样的。

// 窗口类的名称
const wchar_t CLASS_NAME[] = L"Sample Window Class";
// ... 在 WinMain 函数内部 ...
// 1. 注册窗口类
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;         // 指向我们刚才定义的窗口过程函数
wc.hInstance = hInstance;         // 当前实例句柄
wc.lpszClassName = CLASS_NAME;    // 窗口类名
// 加载一个图标(可选)
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// 加载一个光标(可选)
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// 设置窗口的背景色(可选)
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
// 注册窗口类
RegisterClass(&wc);

创建窗口

有了窗口类模板,就可以创建具体的窗口了。

// ... 在 WinMain 函数内部,注册窗口类之后 ...
// 2. 创建窗口
HWND hwnd = CreateWindowEx(
    0,                              // 可选的窗口样式
    CLASS_NAME,                     // 窗口类名
    L"Hello Windows API",          // 窗口标题
    WS_OVERLAPPEDWINDOW,            // 窗口样式
    // 窗口位置和大小
    CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
    NULL,       // 父窗口句柄
    NULL,       // 菜单句柄
    hInstance,  // 实例句柄
    NULL        // 附加创建参数
);
if (hwnd == NULL) {
    return 0; // 创建失败
}
// 3. 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

消息循环

这是程序运行的核心,它会不断地从消息队列中取出消息,并分发给对应的窗口过程函数处理。

// ... 在 WinMain 函数内部,创建并显示窗口之后 ...
// 4. 消息循环
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg); // 翻译键盘消息(如将 WM_KEYDOWN 转为 WM_CHAR)
    DispatchMessage(&msg); // 将消息发送给 WndProc 函数处理
}
// 当 GetMessage 返回 0 时,通常是收到了 WM_QUIT 消息,程序退出
return (int)msg.wParam;

完整代码示例

将以上所有部分组合起来,就是一个完整的、可以运行的 Windows 窗口程序。

c语言 windows编程
(图片来源网络,侵删)
#include <windows.h>
// 窗口过程函数的声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 1. 注册窗口类
    const wchar_t CLASS_NAME[] = L"Sample Window Class";
    WNDCLASS wc = { };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    RegisterClass(&wc);
    // 2. 创建窗口
    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        L"Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style
        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
        NULL,       // Parent window
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );
    if (hwnd == NULL) {
        return 0;
    }
    // 3. 显示窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    // 4. 消息循环
    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}
// 5. 窗口过程函数
LRESULT CALLBACK WndProc(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 使用宽字符,所以字符串前要加 L
            TextOut(hdc, 50, 50, L"Hello, Windows API!", 19);
            EndPaint(hwnd, &ps);
        }
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

如何编译和运行?

  1. Visual Studio: 创建一个新的 "Windows 桌面应用程序" 项目,将代码粘贴进去即可。
  2. MinGW (GCC): 保存为 main.c,然后在命令行运行:
    gcc main.c -o my_win_app.exe -mwindows
    ./my_win_app.exe

运行后,你将看到一个标题为 "Learn to Program Windows" 的窗口,窗口中央有 "Hello, Windows API!" 的文字。


进阶学习方向

掌握了这个基础框架后,你可以探索更广阔的 Windows 编程世界:

  1. 控件:学习创建按钮、编辑框、列表框等标准 Windows 控件。
  2. 资源文件:学习使用 .rc 文件来管理图标、光标、菜单、对话框等资源,而不是用代码硬编码。
  3. 文档/视图架构:这是 MFC (Microsoft Foundation Classes) 框架的核心思想,用于构建更复杂的应用程序。
  4. COM (Component Object Model):Windows 的组件技术,用于创建可复用的软件组件(DirectX 就基于 COM)。
  5. .NET 互操作:如果你的 C 程序需要调用 .NET 的库,可以使用 P/Invoke (Platform Invoke) 技术。
  6. 现代 Windows UI (WinUI 3):微软推出的新一代 UI 框架,用于替代旧的 Win32 API,提供更现代的控件和 XAML 布局,它仍然底层调用 Win32,但提供了更高层次的抽象。

替代方案:MFC 和第三方库

直接使用 Win32 API 虽然强大,但代码量较大,也比较繁琐,社区和微软本身提供了一些封装方案:

  • MFC (Microsoft Foundation Classes):微软官方的 C++ 类库,对 Win32 API 进行了 C++ 风格的面向对象封装,曾经是 Windows C++ 开发的主流。
  • Qt:一个跨平台的 C++ GUI 框架,非常强大和流行,虽然它也支持 Windows,但它的设计理念是“一次编写,到处编译”。
  • wxWidgets:另一个跨平台的 C++ GUI 工具包,模仿了 MFC 的一些设计。
  • Dear ImGui:一个即时模式 (immediate mode) 的 GUI 库,非常适合在游戏、科学可视化、工具开发中快速创建调试界面。

对于纯 C 语言开发者来说,直接使用 Win32 API 是最直接、最根本的学习路径,理解了它,再去学习其他框架的原理也会事半功倍。

-- 展开阅读全文 --
头像
织梦文章描述字数限制是多少?
« 上一篇 03-23
织梦文章如何加标题链接?
下一篇 » 03-23
取消
微信二维码
支付宝二维码

目录[+]