我写了一些代码来确定某个窗口是否在桌面边界内
不知何故,它不起作用。对于每个窗口,无论是在桌面内部还是外部,都会返回false
。这里有些东西是非常错误的,但是现在盯着这段代码3个小时之后,我仍然不知道问题出在哪里。如果我尝试从PMSG的WPARAM中发送的指针读取RECT结构,我会得到一个AccessViolationException。为什么会这样?
我的代码看起来像这样,并且总是返回false:
static bool IsInBounds(HWND window)
{
DEVMODE d;
d.dmSize = sizeof(DEVMODE);
BOOL b = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &d);
if(b == FALSE)
{
PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"FMSG"), (WPARAM)window, NULL);
}
RECT R;
GetWindowRect(window, &R);
POINT p = POINT();
p.x = (LONG)d.dmPelsWidth;
p.y = (LONG)d.dmPelsHeight;
PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"PMSG"), (WPARAM)&R, d.dmPelsWidth);
if(R.right < 0 || R.bottom < 0 || R.left > (LONG)d.dmPelsWidth || R.top > (LONG)d.dmPelsHeight)
{
return false;
}
return true;
}
编辑:
在调用IsInBounds后,它返回错误号1400(无效的窗口句柄),但在从钩子回调返回之前,我调用了IsWindow(window)
,看看我的句柄是否仍然有效。事实是:是契约一个有效的句柄! GetWindowRect如何说它是一个无效的句柄?
编辑: 我尝试将MonitorFromWindow作为sujested,但它返回NULL,并且调用GetLastError导致错误号。 1400,这对我来说已经很熟悉了。看起来MonitorFromWindow隐式调用GetWindowRect。我不关心大小,但是是否有另一种方式从句柄获取窗口坐标?
答案 0 :(得分:4)
PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"PMSG"), (WPARAM)&R, d.dmPelsWidth);
将不起作用,您不能只传递一个RECT指针交叉进程,如果您需要传递大于指针交叉进程的内容,请使用WM_COPYDATA。即使它不是跨进程,你使用PostMessage而不是SendMessage的事实意味着在处理消息时RECT可能超出了范围!
使用EnumDisplaySettings有点矫枉过正,使用MONITOR_DEFAULTTONULL的MonitorFromWindow应该就是您所需要的。
答案 1 :(得分:3)
(1)直截了当
RECT rDesk = { 0 };
GetBystemParametersInfo(SPI_GETWORKAREA, 0, &rDesk, 0);
RECT rWnd;
GetWindowRect(wnd, &rWnd);
POINT pttl = { rWnd.left, rWnd.top);
POINT ptbr = { rWnd.right, rWnd.bottom);
if (PtInRect(&rDesk, pttl) && PtInRect(&rDesk, ptbr))
// ....
SPI_GETWORKAREA查询桌面区域(而不是屏幕,其中包括任务栏等)
将GetSystemParametersInfo替换为GetMonitorInfo
以支持多个监视器。
(2)GetWindowRect
目标窗口是属于提升的进程,还是属于在不同安全上下文中运行的进程?
(3)其他评论
对于RegisterMessage
,请勿使用此类非唯一名称。毕竟,它在全系统工作。我强调在他们的名字中嵌入一个GUID。
已经提到过PostMessage:它是异步的,你可以跨指针传递指针。
我不明白为什么你需要将窗口句柄传递给其他一些不相关的窗口。
答案 2 :(得分:2)
PostMessage()
是异步的,您正在发送指向函数局部变量的指针(RECT R
)。当接收者处理消息时,该局部变量很可能已经消失。
此外,您应该检查GetWindowRect()
的返回值,以确保它没有失败。
另一件事,如果EnumDisplaySettings()
失败,你应该回来。如果DEVMODE d
尚未填写,第16行的测试将是荒谬的。