You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用windows.h创建窗口?能否不引入头文件实现窗口创建?

关于Windows窗口创建底层原理与<windows.h>的疑问解答

一、<windows.h>的内部原理

<windows.h>是Windows SDK提供的核心头文件,本质上是一堆C语言风格的宏定义、数据类型声明、函数原型声明的集合,它本身没有可执行代码,核心作用是给C/C++编译器提供Windows API的接口信息,让你的代码能正确调用系统底层提供的函数。

它会自动包含一系列细分功能的头文件,比如负责窗口管理的<winuser.h>、图形绘制的<wingdi.h>、系统内核功能的<kernel32.h>等,把分散的Windows API接口统一打包暴露给开发者,避免手动逐个引入细分头文件的繁琐。

二、<windows.h>是不是C/C++代码?

是的,它完全由合法的C/C++代码构成(准确说是兼容C的代码,因为Windows API设计时采用C接口以保证跨语言兼容性)。但要明确:它只包含声明,不包含实现——真正的Windows API实现是在系统的动态链接库(如user32.dll、kernel32.dll)里,这些是微软编译好的二进制文件,属于Windows系统的核心组件。

三、能不能不引入任何头文件创建窗口?

可以,但过程非常繁琐,因为你需要手动完成所有原本由头文件提供的工作:

  • 手动声明所有需要的数据类型(如WNDCLASS、MSG)
  • 手动定义所有需要的宏(如CS_HREDRAW、WS_OVERLAPPEDWINDOW,或者直接用它们对应的数值)
  • 手动声明需要调用的Windows API函数原型,还要指定正确的调用约定(比如__stdcall)
  • 编译时必须显式链接对应的系统库(如user32.lib、kernel32.lib)

极简示例(不引入任何头文件)

// 手动声明基本类型
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long LONG;
typedef void* HINSTANCE;
typedef void* HWND;
typedef const char* LPCSTR;
typedef unsigned int WPARAM;
typedef long LPARAM;
typedef int BOOL;

// 手动定义宏
#define CS_HREDRAW 0x0002
#define WS_OVERLAPPEDWINDOW 0x00CF0000
#define SW_SHOW 5
#define WM_DESTROY 0x0002
#define WM_QUIT 0x0012
#define TRUE 1
#define FALSE 0

// 手动声明函数原型(注意__stdcall调用约定)
typedef BOOL (__stdcall* ShowWindowPtr)(HWND, int);
typedef HWND (__stdcall* CreateWindowExPtr)(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, void*, HINSTANCE, void*);
typedef BOOL (__stdcall* RegisterClassPtr)(const void*);
typedef int (__stdcall* MessageBoxPtr)(HWND, LPCSTR, LPCSTR, UINT);
typedef int (__stdcall* GetMessagePtr)(void*, HWND, UINT, UINT);
typedef BOOL (__stdcall* TranslateMessagePtr)(const void*);
typedef LONG (__stdcall* DispatchMessagePtr)(const void*);
typedef void (__stdcall* PostQuitMessagePtr)(int);
typedef HINSTANCE (__stdcall* LoadLibraryPtr)(LPCSTR);
typedef void* (__stdcall* GetProcAddressPtr)(HINSTANCE, LPCSTR);

// 窗口过程函数
LONG __stdcall WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
    if (msg == WM_DESTROY) {
        HINSTANCE user32 = ((LoadLibraryPtr)__builtin_get_proc_address((HINSTANCE)-1, "LoadLibraryA"))("user32.dll");
        PostQuitMessagePtr PostQuitMessage = (PostQuitMessagePtr)((GetProcAddressPtr)__builtin_get_proc_address((HINSTANCE)-1, "GetProcAddress"))(user32, "PostQuitMessage");
        PostQuitMessage(0);
        return 0;
    }
    return 0;
}

// 入口函数
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow) {
    // 获取LoadLibrary和GetProcAddress地址(kernel32.dll已默认加载)
    LoadLibraryPtr LoadLibrary = (LoadLibraryPtr)__builtin_get_proc_address((HINSTANCE)-1, "LoadLibraryA");
    GetProcAddressPtr GetProcAddress = (GetProcAddressPtr)__builtin_get_proc_address((HINSTANCE)-1, "GetProcAddress");
    
    HINSTANCE user32 = LoadLibrary("user32.dll");
    RegisterClassPtr RegisterClass = (RegisterClassPtr)GetProcAddress(user32, "RegisterClassA");
    CreateWindowExPtr CreateWindowEx = (CreateWindowExPtr)GetProcAddress(user32, "CreateWindowExA");
    ShowWindowPtr ShowWindow = (ShowWindowPtr)GetProcAddress(user32, "ShowWindow");
    
    // 手动构造WNDCLASS(成员顺序必须和系统定义完全一致)
    struct WNDCLASS wc = {0};
    wc.style = CS_HREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "RawWindowClass";
    
    RegisterClass(&wc);
    
    HWND hwnd = CreateWindowEx(0, "RawWindowClass", "No-Header Window", WS_OVERLAPPEDWINDOW, 100, 100, 400, 300, 0, 0, hInstance, 0);
    ShowWindow(hwnd, nCmdShow);
    
    // 消息循环
    GetMessagePtr GetMessage = (GetMessagePtr)GetProcAddress(user32, "GetMessageA");
    TranslateMessagePtr TranslateMessage = (TranslateMessagePtr)GetProcAddress(user32, "TranslateMessage");
    DispatchMessagePtr DispatchMessage = (DispatchMessagePtr)GetProcAddress(user32, "DispatchMessageA");
    
    struct MSG msg;
    while (GetMessage(&msg, 0, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    return msg.wParam;
}

注:这个示例用了GCC的内置函数来获取系统函数地址,不同编译器(如MSVC)需要调整对应逻辑。实际运行还需补充窗口过程的默认消息处理等细节,这里为了简化省略了。


内容的提问来源于stack exchange,提问作者Miodek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:47:35