发送WM_GETTITLEBARINFOEX获取标题栏RECT是否存在稳定性或回归问题?
WM_GETTITLEBARINFOEX 返回标题栏RECT异常问题分析与验证
问题现象
- 在Windows 10/11系统中,调用
SendMessage(hwnd, WM_GETTITLEBARINFOEX, 0, (LPARAM)&infoex)获取infoex.rcTitleBar时,存在两个明显异常:- 返回的RECT与系统图标区域重叠
- 底部高度比实际少1像素
- 改用
GetTitleBarInfo(hwnd, &info)函数,或通过以下代码手动计算时,结果完全正常:rcCaption.left = rcIcon.right + ::GetSystemMetrics(SM_CXEDGE)*2; rcCaption.bottom = rcCaption.top + ::GetSystemMetrics(SM_CYCAPTION);
测试验证代码
以下代码可直接在Windows环境下编译运行,对比三种方式的RECT结果:
#include <windows.h> #include <iostream> void TestTitleBarRect(HWND hwnd) { // 测试WM_GETTITLEBARINFOEX TITLEBARINFOEX infoex = {0}; infoex.cbSize = sizeof(TITLEBARINFOEX); SendMessage(hwnd, WM_GETTITLEBARINFOEX, 0, reinterpret_cast<LPARAM>(&infoex)); std::cout << "[WM_GETTITLEBARINFOEX] rcTitleBar: " << "Left=" << infoex.rcTitleBar.left << ", Top=" << infoex.rcTitleBar.top << ", Right=" << infoex.rcTitleBar.right << ", Bottom=" << infoex.rcTitleBar.bottom << "\n"; // 测试GetTitleBarInfo TITLEBARINFO info = {0}; info.cbSize = sizeof(TITLEBARINFO); GetTitleBarInfo(hwnd, &info); std::cout << "[GetTitleBarInfo] rcTitleBar: " << "Left=" << info.rcTitleBar.left << ", Top=" << info.rcTitleBar.top << ", Right=" << info.rcTitleBar.right << ", Bottom=" << info.rcTitleBar.bottom << "\n"; // 手动计算标题栏可绘制区域 RECT rcWindow = {0}; GetWindowRect(hwnd, &rcWindow); RECT rcIcon = {0}; HWND hIconWnd = GetWindow(hwnd, GW_CHILD); if (hIconWnd != nullptr && GetWindowRect(hIconWnd, &rcIcon)) { RECT rcCaption = rcWindow; rcCaption.left = rcIcon.right + GetSystemMetrics(SM_CXEDGE) * 2; rcCaption.bottom = rcWindow.top + GetSystemMetrics(SM_CYCAPTION); std::cout << "[手动计算] rcCaption: " << "Left=" << rcCaption.left << ", Top=" << rcCaption.top << ", Right=" << rcCaption.right << ", Bottom=" << rcCaption.bottom << "\n"; } } int main() { HWND hwnd = GetConsoleWindow(); // 使用当前控制台窗口作为测试对象 TestTitleBarRect(hwnd); system("pause"); return 0; }
问题原因
- 区域范围差异:
WM_GETTITLEBARINFOEX返回的rcTitleBar是标题栏的完整非客户区范围,包含系统图标、最小化/最大化/关闭按钮等所有元素的占位区域;而GetTitleBarInfo返回的是标题栏的可绘制文本区域,已经自动排除了图标和按钮的占用空间。 - 底部像素偏差:
WM_GETTITLEBARINFOEX的RECT计算未包含窗口边框的下边缘像素,而SM_CYCAPTION是系统定义的标准标题栏高度,手动计算时直接使用该值会更准确。
解决方案
- 若需获取标题栏的可绘制区域(排除图标),优先使用
GetTitleBarInfo或手动计算的方式,避免额外修正步骤。 - 若必须使用
WM_GETTITLEBARINFOEX,可对返回的RECT进行手动修正:// 修正左边缘,避开图标区域 infoex.rcTitleBar.left = rcIcon.right + GetSystemMetrics(SM_CXEDGE) * 2; // 修正底部高度,补充缺失的1像素 infoex.rcTitleBar.bottom = infoex.rcTitleBar.top + GetSystemMetrics(SM_CYCAPTION);
内容的提问来源于stack exchange,提问作者Tomay
相关产品推荐
相关产品推荐

