C++调用Windows API创建窗口核心三步:注册窗口类、创建窗口、运行消息循环;缺一不可。WinMain是Windows子系统入口,main仅适用于控制台子系统;hInstance必须正确赋值;RegisterClass失败需检查WndProc、类名唯一性及wc.hInstance;WM_DESTROY中必须调用PostQuitMessage(0)退出消息循环;WindowProc未处理消息须交由DefWindowProc。

直接说结论:C++ 调用 Windows API 创建窗口,核心就三步——注册窗口类、创建窗口、跑消息循环;漏掉任何一步,窗口都出不来,或者一启动就闪退。
为什么 WinMain 不能换成 main?
Windows 桌面程序不是控制台程序,操作系统加载时会找 WinMain 入口,而不是 main。如果你强行写 main,链接器会报错:unresolved external symbol _WinMain@16(尤其在 Visual Studio 新建 Win32 项目时默认设为 Windows 子系统)。
- 必须用
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int),WINAPI是__stdcall调用约定,影响栈清理方式 - 如果想用
main,得手动改子系统为Console并调用AllocConsole()——但这就不是纯 Win32 窗口程序了 -
hInstance是模块句柄,后续注册类、创建窗口都依赖它,不能传错或留空
RegisterClass 失败的常见原因
注册失败不报错,但后续 CreateWindow 一定返回 NULL,且 GetLastError() 通常也拿不到有效信息——因为 RegisterClass 本身不设错误码,只靠返回值判断。
-
WNDCLASS.lpfnWndProc必须是非空函数指针,且该函数必须已定义(不能只声明不实现) -
WNDCLASS.lpszClassName不能重复:若之前注册过同名类(比如调试多次没重启),RegisterClass会失败 -
WNDCLASS.hbrBackground若用GetStockObject,记得加(HBRUSH)强转;用COLOR_WINDOW+1则必须配合(HBRUSH)类型转换,否则编译可能过、运行时背景异常 - 别忘了
wc.hInstance = hInstance——漏这行是新手高频失误
GetMessage 卡死?你可能没处理 WM_DESTROY
消息循环卡在 GetMessage 不动,表面看是“程序假死”,实际往往是窗口关闭后没发 WM_QUIT,导致循环无法退出。
立即学习“C++免费学习笔记(深入)”;
-
WM_DESTROY中必须调用PostQuitMessage(0),这是唯一可靠触发GetMessage返回FALSE的方式 - 别在
WM_CLOSE里直接DestroyWindow或PostQuitMessage——标准做法是DefWindowProc处理WM_CLOSE,再由系统发WM_DESTROY - 如果用了
PeekMessage做非阻塞轮询,要小心无限空转吃满 CPU,务必加WaitMessage()或短延时
WindowProc 里忘记 return DefWindowProc 会怎样?
所有未显式处理的消息(比如 WM_NCCREATE、WM_GETMINMAXINFO、菜单/拖拽相关消息)都必须交给系统默认处理。漏掉这句,窗口可能无法移动、缩放、显示标题栏,甚至点叉号都没反应。
- 每个
case分支末尾必须有return,不要靠函数结尾隐式返回 -
DefWindowProc的四个参数必须原样传入,尤其是hwnd——不能传错句柄或NULL - 如果自定义了绘图逻辑(如
WM_PAINT),记得调用BeginPaint/EndPaint,否则窗口内容残留、闪烁严重
真正难的不是写完能弹窗的代码,而是让窗口行为符合 Windows 用户直觉:Alt+Tab 能切、任务栏有图标、最小化后双击能恢复、DPI 缩放不糊……这些全藏在 WNDCLASS 配置、消息分支细节和资源释放逻辑里。初学者容易盯着“窗口出来了”就停手,但生产级 Win32 程序,90% 的工作量都在处理那些“本该自动发生却没发生”的事。











