我有一个经典的Win32-API(C ++)应用程序,需要检测窗口是否停靠在屏幕的左/右半部分。
问题的背景是窗口只有网格步长,比方说32像素。在全屏幕中,程序检测到该状态,允许大小与全屏匹配并填充多余空间。对于Windows 8及更高版本,我想做同样的事情而不是当前离开边框(因为大小会捕捉到32像素的倍数)。
答案 0 :(得分:3)
使用函数GetWindowPlacement()
,您可以使用rcNormalPosition
的成员WINDOWPLACEMENT
检索普通窗口矩形。然后将法线矩形与实际窗口矩形进行比较。如果他们不匹配,窗口最有可能处于停靠状态。
示例:
bool IsDockedToMonitor(HWND hWnd)
{
WINDOWPLACEMENT placement = {sizeof(WINDOWPLACEMENT)};
GetWindowPlacement(hWnd, &placement);
RECT rc;
GetWindowRect(hWnd, &rc);
return placement.showCmd == SW_SHOWNORMAL
&& (rc.left != placement.rcNormalPosition.left ||
rc.top != placement.rcNormalPosition.top ||
rc.right != placement.rcNormalPosition.right ||
rc.bottom != placement.rcNormalPosition.bottom);
}
请注意,此解决方案在100%的时间内都不可靠。即使窗口停靠在显示器侧面,普通矩形和当前窗口矩形也很有可能匹配。
答案 1 :(得分:2)
除了IInspectable已经提到过的内容之外,还有另一种方法可以确定这些信息并采取相应的行动。
WM_WINDOWPOSCHANGED
消息,并从存储在其中的WINDOWPOS
指针中读取其x
,y
,cx
和cy
值lParam
。MonitorFromWindow
来获取放置窗口的当前监视器的句柄。MONITORINFO
变量并将其cbSize
字段设置为sizeof(MONITORINFO)
。MONITORINFO
变量的地址来呼叫GetMonitorInfo
。 rcWork
变量中读取MONITORINFO
值。
rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcWork.left == WINDOWPOS.x
- 窗口是"停靠"在左边rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcwork.right == (WINDOWPOS.x + WINDOWPOS.cx)
- 窗口是"停靠" rcWork.top == WINDOWPOS.y && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx)
- 窗口是"停靠" rcWork.top == (WINDOWPOS.y + WINDOWPOS.cy) && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx)
- 窗口是"停靠" 你说你已经有逻辑确定窗口是全屏的(你的意思是全屏还是最大化?),但是如果left == x && top == y && right == x + cx && bottom == y + cy
可以确定有效的最大化。
Here is an MSDN example of something similar.
请注意,可能需要缓存MONITORINFO
值,以便每次重新定位窗口时都不需要调用它。
如果您只想在用户不手动调整窗口大小时应用此项,那么这是一个人为的示例,说明了这样做:
LRESULT CALLBACK windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
static bool userSizing = false;
switch (msg)
{
// could also catch WM_ENTERSIZEMOVE here, but this will trigger on
// moves as well as sizes
case WM_SIZING:
userSizing = true;
break;
case WM_EXITSIZEMOVE:
userSizing = false;
break;
case WM_WINDOWPOSCHANGED:
if (userSizing)
{
break;
}
// do logic to check to see if the window is sized in a "docked"
// manner here
break;
// handle other window messages ...
}
}
答案 2 :(得分:1)
Aero Snap 功能内置于Shell中,而不是窗口管理器。因此,没有特定的窗口样式或标志指示停靠状态。 Shell只是重新定位窗口以响应某些操作(并在内部记录状态)。它的实现方式与使用鼠标或键盘手动重新定位窗口无法区分。
您无法可靠地确定窗口是否停靠在屏幕的左侧或右侧。壳牌公司没有发送任何特定信息,窗户的相对于工作区域的大小和位置也没有足够的财产。
你想要完成的是不可能的。您必须实施一个解决方案,该解决方案不需要不可用的信息。一种这样的实现方式是始终对窗口大小使用填充,这不允许使用整个客户区域。另一种解决方案是实现相反的方法:允许窗口调整大小为任意大小,除非您知道用户正在手动调整窗口大小。您可以通过处理WM_SIZING消息来确定后者。