Win32程序启动时WM_SIZE消息返回错误窗口尺寸的原因及解决方法咨询
关于OpenGL窗口初始WM_SIZE尺寸偏差的问题解答
这是Windows窗口开发里挺常见的一个小坑,我来给你捋清楚原因和解决办法:
一、启动时WM_SIZE消息发送的原因
当你调用CreateWindowEx创建窗口后,Windows系统会完成窗口的初始化布局——确定窗口的位置、大小,然后自动给窗口发送WM_SIZE消息,目的是通知你的程序:“窗口尺寸已经确定啦,快更新你的渲染区域和布局!” 这是窗口创建流程里的标准步骤,不管你有没有手动调整窗口,都会触发这一次初始的WM_SIZE。
二、初始尺寸偏差的核心原因
你搞混了窗口整体尺寸和客户区尺寸的区别:
- 你在
CreateWindowEx里传入的1280, 720是整个窗口的大小,包括标题栏、窗口边框这些非客户区部分; - 而
WM_SIZE消息的lParam返回的是客户区的尺寸——也就是你实际用来绘制OpenGL内容的区域,这部分是要扣除标题栏和边框宽度的。
你看到的1260×677,正好是1280减去左右边框的总宽度、720减去标题栏高度加上上下边框总高度后的结果,完全符合Windows窗口的尺寸计算逻辑。
至于手动调整窗口后尺寸正常,是因为当你拖动窗口时,系统会根据你调整的边界(不管是拖边框还是客户区),重新计算并返回准确的客户区尺寸,这时候你视觉上看到的窗口大小和实际客户区的对应关系是匹配的,所以点击区域就正常了。
三、解决方案
1. 从根源解决:创建时指定客户区尺寸(推荐)
用AdjustWindowRectEx函数,根据你想要的客户区尺寸,反向计算出需要的窗口整体尺寸,再传给CreateWindowEx。这样初始的WM_SIZE返回的客户区就会正好是你要的1280×720。
代码示例:
// 定义你想要的客户区尺寸 RECT desiredClientRect = {0, 0, 1280, 720}; // 根据窗口样式计算所需的整体窗口尺寸 AdjustWindowRectEx(&desiredClientRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_OVERLAPPEDWINDOW); // 创建窗口,传入计算后的整体尺寸 MainWindow.handle = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, windowClass.lpszClassName, "Some window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, desiredClientRect.right - desiredClientRect.left, // 窗口宽度 desiredClientRect.bottom - desiredClientRect.top, // 窗口高度 NULL, NULL, instance, NULL );
2. 手动发送WM_SIZE消息(不推荐,仅作补充)
如果你暂时不想改窗口创建逻辑,也可以在窗口创建完成后,手动发送一条WM_SIZE消息,强制设置客户区尺寸:
// 窗口创建后调用 SendMessage(MainWindow.handle, WM_SIZE, 0, MAKELPARAM(1280, 720));
但这种方法是“治标不治本”,因为初始的客户区实际尺寸还是小的,只是强制让你的程序用1280×720来渲染,可能会导致渲染内容和实际窗口区域不匹配,还是优先用第一种方法更稳妥。
内容的提问来源于stack exchange,提问作者TopTofu
相关产品推荐
相关产品推荐

