C语言CreateWindows函数如何正确创建窗口?

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

CreateWindow 是 Windows API(应用程序编程接口)中的一个核心函数,用于在内存中创建(或称“生成”)一个窗口,这个函数非常重要,它是所有图形用户界面程序的起点。

c语言createwindows
(图片来源网络,侵删)

CreateWindow 是什么?

CreateWindow 函数的作用是根据你提供的参数,在系统中注册并创建一个窗口的“对象”,你可以把它想象成在图纸上设计一个房子的蓝图,这个蓝图定义了房子的名字、大小、样式、拥有者等信息,但房子本身还不存在,你只是创建了这个设计。

这个函数返回一个窗口句柄,这是一个唯一的标识符(通常是一个 HWND 类型的值),程序后续通过这个句柄来操作这个窗口,比如显示它、移动它、向它发送消息等。


函数原型

CreateWindow 有两个版本:一个用于 ANSI 字符集,一个用于 Unicode 字符集,在 Windows 中,推荐使用 Unicode 版本,因为它能更好地支持多语言环境。

// Unicode 版本 (推荐)
HWND CreateWindowW(
  LPCWSTR    lpClassName,  // 窗口类名
  LPCWSTR    lpWindowName, // 窗口标题
  DWORD      dwStyle,      // 窗口样式
  int        X,            // 初始 x 坐标
  int        Y,            // 初始 y 坐标
  int        nWidth,       // 初始宽度
  int        nHeight,      // 初始高度
  HWND       hWndParent,   // 父窗口句柄
  HMENU      hMenu,        // 窗口菜单句柄
  HINSTANCE  hInstance,    // 应用程序实例句柄
  LPVOID     lpParam       // 创建参数
);
// ANSI 版本 (不推荐,除非有特殊需求)
HWND CreateWindowA(
  LPCSTR     lpClassName,
  LPCSTR     lpWindowName,
  DWORD      dwStyle,
  int        X,
  int        Y,
  int        nWidth,
  int        nHeight,
  HWND       hWndParent,
  HMENU      hMenu,
  HINSTANCE  hInstance,
  LPVOID     lpParam
);

在 Visual Studio 中,如果你包含 <windows.h> 并调用 CreateWindow,预处理器会根据项目设置(Unicode/多字节字符集)自动将其解析为 CreateWindowWCreateWindowA

c语言createwindows
(图片来源网络,侵删)

参数详解

理解每个参数的含义是使用 CreateWindow 的关键。

参数 类型 描述
lpClassName LPCWSTR 窗口类名,这是一个字符串,用于标识窗口的“模板”,你不能直接创建一个没有任何定义的窗口,这个类名必须是一个已经注册的窗口类,注册通常通过 RegisterClassEx 函数完成,你也可以使用一些预定义的类名,如 TEXT("BUTTON"), TEXT("EDIT"), TEXT("STATIC") 等。
lpWindowName LPCWSTR ,这是显示在窗口标题栏上的文本,对于按钮等控件,这通常是按钮上显示的文字。
dwStyle DWORD 窗口样式,这是一个或多个使用按位或 () 运算符组合起来的标志,常用样式有:
- WS_OVERLAPPED: 创建一个带边框和标题栏的顶层窗口。
- WS_CAPTION: 创建一个带标题栏的窗口(必须与 WS_OVERLAPPED 组合)。
- WS_SYSMENU: 在标题栏上添加一个系统菜单(关闭按钮等)。
- WS_THICKFRAME: 创建一个可调整大小的窗口边框。
- WS_MINIMIZEBOX: 添加最小化按钮。
- WS_MAXIMIZEBOX: 添加最大化按钮。
- WS_VISIBLE: 非常重要! 创建窗口后立即显示它,如果不加这个标志,窗口虽然被创建,但不可见。
- WS_POPUP: 创建一个弹出式窗口。
- WS_CHILD: 创建一个子窗口(控件)。
常用组合:WS_OVERLAPPEDWINDOW = WS_OVERLAPPED \| WS_CAPTION \| WS_SYSMENU \| WS_THICKFRAME \| WS_MINIMIZEBOX \| WS_MAXIMIZEBOX
X int 窗口左上角的初始 x 坐标(相对于屏幕左上角),使用 CW_USEDEFAULT 可以让系统自动选择一个默认位置。
Y int 窗口左上角的初始 y 坐标,同样可以使用 CW_USEDEFAULT
nWidth int 窗口的初始宽度(以像素为单位),使用 CW_USEDEFAULT 可以让系统自动选择一个默认宽度。
nHeight int 窗口的初始高度(以像素为单位)。
hWndParent HWND 父窗口句柄,如果创建的是子窗口或控件,这里应填入父窗口的句柄,对于顶层窗口,此项为 NULL
hMenu HMENU 窗口菜单句柄,对于顶层窗口,通常为 NULL,对于子窗口(控件),它被用作控件的 ID。
hInstance HINSTANCE 应用程序实例句柄,在 WinMain 函数中,这个值由系统传入,你可以使用全局变量 GetModuleHandle(NULL) 来获取它。
lpParam LPVOID 创建参数,这是一个指向任意数据的指针,用于向窗口过程传递初始化数据,对于大多数简单窗口,此项为 NULL

完整示例:创建并显示一个窗口

下面是一个完整的 C 语言程序,它演示了如何注册一个窗口类,然后使用 CreateWindow 创建并显示这个窗口。

#include <windows.h>
// 窗口过程函数的声明
// LRESULT 是一个 32 位或 64 位的整数,取决于平台
// CALLBACK 是一个调用约定
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 1. 定义窗口类
    WNDCLASSEXW wcex = { 0 };
    wcex.cbSize = sizeof(WNDCLASSEXW);
    wcex.style = CS_HREDRAW | CS_VREDRAW; // 类样式
    wcex.lpfnWndProc = WndProc;           // 指向窗口过程函数的指针
    wcex.cbClsExtra = 0;                  // 类的额外内存
    wcex.cbWndExtra = 0;                  // 窗口的额外内存
    wcex.hInstance = hInstance;           // 应用程序实例句柄
    wcex.hIcon = LoadIconW(NULL, IDI_APPLICATION); // 默认图标
    wcex.hCursor = LoadCursorW(NULL, IDC_ARROW);   // 默认光标
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 背景画刷
    wcex.lpszClassName = L"MyWindowClass";         // 窗口类名
    wcex.hIconSm = LoadIconW(NULL, IDI_APPLICATION); // 小图标
    // 2. 注册窗口类
    if (!RegisterClassExW(&wcex)) {
        MessageBoxW(NULL, L"窗口类注册失败!", L"错误", MB_OK);
        return 1;
    }
    // 3. 创建窗口
    HWND hWnd = CreateWindowW(
        L"MyWindowClass",   // 窗口类名 (必须和注册时的一致)
        L"我的第一个窗口",  // 窗口标题
        WS_OVERLAPPEDWINDOW, // 窗口样式
        CW_USEDEFAULT,       // x 坐标
        CW_USEDEFAULT,       // y 坐标
        800,                 // 宽度
        600,                 // 高度
        NULL,                // 父窗口句柄
        NULL,                // 菜单句柄
        hInstance,           // 应用程序实例句柄
        NULL                 // 创建参数
    );
    // 检查窗口是否创建成功
    if (!hWnd) {
        MessageBoxW(NULL, L"窗口创建失败!", L"错误", MB_OK);
        return 1;
    }
    // 4. 显示和更新窗口
    ShowWindow(hWnd, nCmdShow); // nCmdShow 决定了窗口的初始显示状态(正常、最大化、最小化等)
    UpdateWindow(hWnd);         // 强制立即重绘窗口客户区
    // 5. 消息循环
    MSG msg;
    while (GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg); // 翻译键盘消息
        DispatchMessageW(&msg); // 将消息发送到窗口过程函数处理
    }
    return (int)msg.wParam;
}
// 6. 窗口过程函数 - 这是窗口的“大脑”
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // 在这里进行绘制操作
        TextOutW(hdc, 50, 50, L"你好, CreateWindow!", 20);
        EndPaint(hWnd, &ps);
    }
        break;
    case WM_DESTROY: {
        // 当用户点击关闭按钮时,发送 WM_DESTROY 消息
        PostQuitMessage(0); // 发送 WM_QUIT 消息,使 GetMessage 返回 0,从而结束消息循环
    }
        break;
    default:
        // 对于我们没有处理的消息,交给系统默认处理
        return DefWindowProcW(hWnd, message, wParam, lParam);
    }
    return 0;
}

代码解释:

  1. WinMain: 这是 Windows 程序的入口点,类似于控制台程序的 main
  2. WNDCLASSEXW 结构体: 定义了窗口的“蓝图”或“模板”,它告诉系统这个窗口应该用什么函数来处理消息(lpfnWndProc),它长什么样(图标、光标、背景色)等等。
  3. RegisterClassExW: 将 WNDCLASSEXW 结构体注册到系统中,只有注册后,才能用这个类名来创建窗口。
  4. CreateWindowW: 根据注册好的 MyWindowClass 这个模板,在内存中创建一个具体的窗口实例。
  5. ShowWindowUpdateWindow: CreateWindow 只是创建了窗口对象,但你看不见它。ShowWindow 负责将它显示在屏幕上,UpdateWindow 确保窗口的初始内容被绘制出来。
  6. 消息循环: 这是 Windows GUI 程序的核心,程序会一直循环,等待用户的各种操作(如点击鼠标、敲击键盘),这些操作会转换成消息,被放入消息队列。GetMessage 从队列中取出消息,DispatchMessage 将消息发送给对应的窗口过程函数 (WndProc) 处理。
  7. WndProc (窗口过程函数): 这是真正处理消息的地方。switch 语句根据不同的消息代码(message)执行不同的代码,我们只处理了 WM_PAINT(需要重绘时)和 WM_DESTROY(窗口被销毁时)两个消息,其他所有消息都通过 DefWindowProcW 交由系统处理。

CreateWindow vs. CreateWindowEx

你还会看到一个功能更强大的函数:CreateWindowEx

CreateWindowExCreateWindow 几乎完全相同,但它多了一个 dwExStyle 参数。

c语言createwindows
(图片来源网络,侵删)

dwExStyle 用于指定扩展窗口样式,这些是标准窗口样式无法实现的更高级的特性。

  • WS_EX_CLIENTEDGE: 给窗口客户区添加一个凹陷的边框。
  • WS_EX_TOOLWINDOW: 创建一个工具栏窗口,不出现在任务栏上。
  • WS_EX_LAYERED: 创建一个分层窗口,支持透明效果。

除非你需要使用扩展样式,否则 CreateWindowCreateWindowEx 可以互换使用。CreateWindowEx 是更现代和推荐的选择,因为它提供了更多的灵活性。


  • CreateWindow 的核心作用是创建一个窗口对象,并返回其句柄
  • 它需要一个已注册的窗口类名作为模板,这个类名通常通过 RegisterClassEx 注册。
  • 通过组合窗口样式 参数,你可以定义窗口的外观和行为(如是否可调整大小、是否有标题栏等)。
  • CreateWindow 只是创建了窗口,要让它显示出来,还需要调用 ShowWindow
  • CreateWindow 创建的窗口本身什么也做不了,你需要通过消息循环窗口过程函数 来响应用户的交互。
-- 展开阅读全文 --
头像
CalculateGood如何实现C语言计算功能?
« 上一篇 2025-12-21
织梦GBK与UTF-8编码到底有啥区别?
下一篇 » 2025-12-21

相关文章

取消
微信二维码
支付宝二维码

目录[+]