我正在尝试将对话框窗口放在桌面的顶部或底部边框旁边。
代码:
CRect MonitorWorkingArea(HMONITOR monitor)
{
MONITORINFOEX monInfo;
zeroVar(monInfo);
monInfo.cbSize = sizeof(monInfo);
GetMonitorInfo(monitor, &monInfo);
return monInfo.rcWork;
}
CRect MonitorWorkingArea_Wnd(HWND hwnd)
{
return MonitorWorkingArea(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST));
}
CRect MonitorWorkArea_Wnd(CWnd& wnd)
{
return MonitorWorkingArea_Wnd(wnd.GetSafeHwnd());
}
void CMyDialog::SetDefaultWndPos(bool toBottom)
{
// Here we can be sure, that
// a) parent of this window is not null, is visible, not minimized
// b) this window smaller than working area of desktop
// c) it has WS_POPUP style
CRect rcThis;
GetWindowRect(&rcThis);
// Shift our rectangle to most upper or most bottom position
const CRect rcDesktop = MonitorWorkingArea_Wnd(*this);
rcThis.MoveToY(toBottom ? rcDesktop.bottom - rcThis.Height() : 0);
// Move window
SetWindowPos(NULL, rcThis.left, rcThis.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
实际代码有点复杂,为简单起见省略了一些检查和功能。
我有两台显示器,都是1920×1080,在虚拟坐标空间中,它们正在铺设:
当窗口放在主监视器上时,上面的代码工作正常,但是在辅助监视器上,它可以意外地工作:它根据窗口的父窗口居中。
例如我正在调用SetDefaultWndPos(false)
并且rc这被计算为{left:2710, top:0, right:3423, bottom:550}
。因此SetWindowPos
调用零y
:
SetWindowPos(NULL, 2710, 0, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
但是在WM_WINDOWPOSCHANGING
void CMyDialog::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
__super::OnWindowPosChanging(lpwndpos);
}
我在调试x = 2710
(未更改)和y = 475
(意外)中看到。接下来,我在Spy实用程序中检查对话框的y位置,它是475.对话窗口看起来像是在它的父窗口的中心。
所有它看起来像是一个操作系统错误地将请求的窗口位置检测为桌面外并使用了一些默认定位。
我发现只有workarund是减少每边1个像素的桌面工作区域:
CRect MonitorWorkingArea(HMONITOR monitor)
{
MONITORINFOEX monInfo;
zeroVar(monInfo);
monInfo.cbSize = sizeof(monInfo);
GetMonitorInfo(monitor, &monInfo);
CRect rc = monInfo.rcWork;
if( !(monInfo.dwFlags & MONITORINFOF_PRIMARY) )
{
++rc.left;
++rc.top;
--rc.right;
--rc.bottom;
}
return rc;
}
它有效,但看起来很奇怪丑陋的黑客。
有人可以解释一下这里发生了什么,并帮助我做出正确的决定吗?
可以依赖操作系统版本吗? (我使用的是Windows 7 Professional SP1)。