我正在开发一款以网格样式在屏幕上定位窗口的应用。在Windows 10上运行时,窗口之间存在巨大差距。进一步调查显示,GetWindowRect
正在返回意外值,包括一个不可见的边框,但我无法通过可见边框返回实际值。
1)This thread表明这是设计的,你可以修复"通过链接winver = 6。我的环境不允许这样做但我已经尝试将PE MajorOperatingSystemVersion
和MajorSubsystemVersion
更改为6而没有任何影响
2)同一个线程还建议使用DwmGetWindowAttribute
和DWMWA_EXTENDED_FRAME_BOUNDS
来获取DWM的真实坐标,这可以正常工作,但意味着改变到达窗口坐标的所有位置。它也不允许设置值,让我们反转过程以便能够设置窗口大小。
3)This question表明在此过程中缺乏DPI意识。无法在清单中设置DPI感知标志,或者调用SetProcessDpiAwareness
都有任何结果。
4)一时兴起,我还尝试添加Windows Vista,7,8,8.1和10兼容性标记,并且Windows主题清单没有任何变化。
这个窗口移动到0x0,1280x1024,据说可以填满整个屏幕,当查询坐标时,我们得到相同的值。 然而,窗口实际上是14像素更窄,以考虑旧版Windows上的边框。
如何说服Windows让我使用真实的窗口坐标?
答案 0 :(得分:19)
Windows 10在左侧,右侧和底部都有薄的不可见边框,用于抓住鼠标进行大小调整。边框可能如下所示:7,0,7,7
(左,上,右,下)
当您致电SetWindowPos
将窗口置于此坐标时:
0, 0, 1280, 1024
窗口将选择那些精确的坐标,GetWindowRect
将返回相同的坐标。但在视觉上,窗口似乎在这里:
7, 0, 1273, 1017
你可以欺骗窗户并告诉它去这里:
-7, 0, 1287, 1031
为此,我们获得Windows 10边框厚度:
RECT rect, frame;
GetWindowRect(hwnd, &rect);
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));
//rect should be `0, 0, 1280, 1024`
//frame should be `7, 0, 1273, 1017`
RECT border;
border.left = frame.left - rect.left;
border.top = frame.top - rect.top;
border.right = rect.right - frame.right;
border.bottom = rect.bottom - frame.bottom;
//border should be `7, 0, 7, 7`
然后像这样偏移矩形:
rect.left -= border.left;
rect.top -= border.top;
rect.right += border.left + border.right;
rect.bottom += border.top + border.bottom;
//new rect should be `-7, 0, 1287, 1031`
除非有更简单的解决方案!
答案 1 :(得分:0)
如何说服Windows让我使用真实的窗口坐标?
您已经在使用真实坐标。 Windows10只是选择隐藏你眼睛的边框。但尽管如此,他们仍然存在。将鼠标悬停在窗口边缘后,光标将变为调整大小光标,这意味着它实际上仍在窗口上方。
如果您希望您的眼睛与Windows告诉您的相符,您可以尝试使用Aero Lite主题公开这些边框以便再次显示它们:
http://winaero.com/blog/enable-the-hidden-aero-lite-theme-in-windows-10/
答案 2 :(得分:0)
AdjustWindowRectEx
(或在Windows 10和更高版本的AdjustWindowRectExForDpi
上)可能有用。这些功能会将客户端矩形转换为窗口大小。
我想您虽然不想重叠边界,所以这可能不是一个完整的解决方案-但这可能是解决方案的一部分,可能对遇到此问题的其他人有用。 / p>
这是我的代码库中的一个简短代码段,在该代码段中,我已成功地使用它们来设置窗口大小以获得所需的客户端大小,请原谅错误处理宏:
DWORD window_style = (DWORD)GetWindowLong(global_context->window, GWL_STYLE);
CHECK_CODE(window_style);
CHECK(window_style != WS_OVERLAPPED); // Required by AdjustWindowRectEx
DWORD window_style_ex = (DWORD)GetWindowLong(global_context->window, GWL_EXSTYLE);
CHECK_CODE(window_style_ex);
// XXX: Use DPI aware version?
RECT requested_size = {};
requested_size.right = width;
requested_size.bottom = height;
AdjustWindowRectEx(
&requested_size,
window_style,
false, // XXX: Why always false here?
window_style_ex
);
UINT set_window_pos_flags = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
CHECK_CODE(SetWindowPos(
global_context->window,
nullptr,
0,
0,
requested_size.right - requested_size.left,
requested_size.bottom - requested_size.top,
set_window_pos_flags
));
在上述用例中仍然存在两个歧义:
答案 3 :(得分:-1)
您可以回复WM_NCCALCSIZE
消息,修改WndProc
的默认行为以删除不可见的边框。
当this document和this document解释时,wParam
> 0,On request wParam.Rgrc[0]
包含窗口的新坐标,当过程返回时,Response wParam.Rgrc[0]
包含新客户矩形的坐标。
golang代码示例:
case win.WM_NCCALCSIZE:
log.Println("----------------- WM_NCCALCSIZE:", wParam, lParam)
if wParam > 0 {
params := (*win.NCCALCSIZE_PARAMS)(unsafe.Pointer(lParam))
params.Rgrc[0].Top = params.Rgrc[2].Top
params.Rgrc[0].Left = params.Rgrc[0].Left + 1
params.Rgrc[0].Bottom = params.Rgrc[0].Bottom - 1
params.Rgrc[0].Right = params.Rgrc[0].Right - 1
return 0x0300
}