3

我写了一些代码来确定某个窗口是否在桌面范围内。
不知何故,它不起作用。对于每个窗口,无论它是在桌面内部还是外部,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。我不在乎大小,但是还有另一种方法可以从句柄获取窗口坐标吗?

4

3 回答 3

4

PostMessage(FindWindow(NULL, L"Window #1"), RegisterWindowMessage(L"PMSG"), (WPARAM)&R, d.dmPelsWidth);如果“Window #1”在另一个进程中将不起作用,您不能只传递 RECT 指针跨进程,如果您需要传递大于指针跨进程的东西,请使用 WM_COPYDATA。即使它不是跨进程,您使用 PostMessage 而不是 SendMessage 的事实也意味着在处理消息时 RECT 可能超出范围!

使用 EnumDisplaySettings 有点矫枉过正,MonitorFromWindow和 MONITOR_DEFAULTTONULL 应该是你所需要的。

于 2011-01-22T17:46:21.370 回答
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 已经提到:它是异步的,你可以跨进程传递指针。

我不明白为什么需要将窗口句柄传递给其他不相关的窗口。

于 2011-01-22T21:19:12.613 回答
2

PostMessage()是异步的,并且您正在发送指向函数 ( RECT R) 的局部变量的指针。当接收者开始处理消息时,该局部变量很可能已经消失了。

此外,您应该检查 的返回值GetWindowRect()以确保它没有失败。

另一件事,如果EnumDisplaySettings()失败,您可能应该返回。DEVMODE d如果没有填写,第 16 行的测试将毫无意义。

于 2011-01-22T17:59:22.413 回答