在桌面开发时,我们有时会创建样式为 WS_POPUP 的窗口,然后自绘标题栏。当窗口最大化时,会覆盖整个屏幕,盖住了任务栏,这通常不是我们想要的效果。

为了避免遮挡任务栏,一般的做法是响应 WM_GETMINMAXINFO 消息,限制其最大化后的位置,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| void CwspopupmaximizeDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
HMONITOR monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONULL);
if (monitor)
{
// 获取窗口所在屏幕
MONITORINFO info = { 0 };
info.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(monitor, &info))
{
// 限制为工作区范围
CRect rcWork = info.rcWork;
lpMMI->ptMaxPosition = { 0, 0 };
lpMMI->ptMaxSize.x = rcWork.Width();
lpMMI->ptMaxSize.y = rcWork.Height();
}
}
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
|
写个测试程序、编译、运行,效果完美

然而当多屏幕时,把测试程序放到副屏幕上,最大化后窗口不但遮住了任务栏,而且横向也超出屏幕,被截掉一部分。

查阅 MSDN 中关于 **MINMAXINFO**** 结构的描述**
如果窗口位于第二屏,MINMAXINFO 中的坐标会进行一些 转换 然后再应用到第二屏上。但究竟是什么转换呢,MSDN 上没有明确指出。
经过搜寻,在微软 The Old New Thing 中找到了进一步的描述:
如此一来就能解释之前的问题了,我的主屏是 1920x1080, 第二屏是 2560x1440,当在第二屏上最大化时,得到的第二屏桌面大小为 2560x1410,超出了主屏大小,所以得按照差值方式调整。
要解决此问题,我们可以在 WM_SIZE 中判断 nType == SIZE_MAXIMIZED 时,修正窗口大小:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| void CwspopupmaximizeDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
if (nType == SIZE_MAXIMIZED)
{
SetDlgItemText(ID_MAXMIZE_RESTORE, L"restore");
HMONITOR monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONULL);
if (monitor)
{
MONITORINFO info = { 0 };
info.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(monitor, &info))
{
CRect rcWork = info.rcWork;
SetWindowPos(NULL, rcWork.left, rcWork.top, rcWork.Width(), rcWork.Height(), SWP_SHOWWINDOW);
}
}
}
else if (nType == SIZE_RESTORED)
{
SetDlgItemText(ID_MAXMIZE_RESTORE, L"maximize");
}
Invalidate();
}
|
参考资料:
How does the window manager adjust ptMaxSize and ptMaxPosition for multiple monitors?