高 DPI 缩放、鼠标挂钩和 WindowFromPoint

High DPI scaling, mouse hooks and WindowFromPoint

我有一个设置 SetWindowsHookEx(WH_MOUSE_LL, , ,) 右键单击​​挂钩的进程。我的进程在 Window 10.0.10586 上设置为 DPI 系统感知,在两个显示器上缩放比例为 150%。这是通过调用 SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE).

设置的

我的问题场景是Office 2007 不支持 DPI,所以让我们将 MS Word 放在屏幕的右四分之一处。右击右下角任务栏上方,鼠标钩发送坐标 1279、675 - 缩放到 Word。然后我右键单击 visual studio(DPI 感知),在屏幕上将近四分之三,鼠标钩向我发送坐标,例如来自 Visual Studio 的 1279、1008。因此,如果我点击屏幕上方的位置,我可能会得到相同的 1279、675。

我的进程试图通过调用 WindowFromPoint API 来确定哪个 window 在该点,但是在这种情况下这显然会失败,因为两个应用程序“共享”相同点。

是否可以强制鼠标挂钩始终发送原始物理坐标,而不是那些缩放到 DPI 不感知应用程序的坐标?如果是这样,怎么办?或者,是否有其他方法可以通过鼠标挂钩确定 hWndprocessID

因为进程是 DPI 感知的,所以在鼠标钩子回调处理程序中调用 GetCursorPos() 总是获取原始物理坐标,而不是按比例缩放到应用程序的逻辑坐标。只需丢弃传递给鼠标回调的坐标。

添加于 2016 年 9 月 30 日

尽管 GetMessagePos 似乎有可能,但如果进程未虚拟化 dpi,则仅 returns 候选它是正确的坐标。

例如

VOID MessagePump()
{
    MSG     messageGet = { 0 };
    DWORD   dwPos;
    POINTS  p;

    while (GetMessage(&messageGet,NULL,0,0)) 
    {
        dwPos = GetMessagePos();
        p = MAKEPOINTS( dwPos );
        TranslateMessage( &messageGet );
        DispatchMessage( &messageGet );
    }
}

鼠标回调处理程序在 GetMessage() 调用期间被调用,但这不会获取正确的物理坐标,其中 DPI 虚拟化对于进程是活动的。例如物理 x = 1909, y = 1072 返回为 1091, 612 缩放比例为 175%,虽然在算术上是正确的,但这并不是所需要的。

Microsoft 在 10.0.14393 中修复了它。

您的客户端网络中现在应该没有任何内部版本号较低的东西,除非它们在 LTSB 10.0.10240 上。

这是解决方案: