1

我有以下鼠标钩子程序(为解释而简化)。

SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, GetModuleHandle(NULL), 0) ;

LRESULT mouseHookProc(int code, WPARAM wParam, LPARAM lParam){
    if(code==HC_ACTION){
        const auto& data = *(MSLLHOOKSTRUCT*)lParam ;
        
        data.pt ; //This point gives physical coordinates. It ignores the monitor's scaling factor.
        //https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msllhookstruct
    }
    return CallNextHookEx(NULL, code, wParam, lParam) ;
}

我从钩子中获得的鼠标坐标不会由显示器的缩放因子调整。
无论我将显示器的缩放系数设置为 100% 还是 200%,鼠标钩总是给我物理像素。

另一方面,GetCursorPoswinapi 函数以逻辑像素给出坐标。即如果缩放因子为200%,GetCursorPos将给出除以2的坐标,而鼠标钩将给出未调整的数字。

据此:
https ://docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/ne-shellscalingapi-process_dpi_awareness

如果程序支持 DPI,系统会补偿缩放因子,以便程序继续工作,就好像什么都没发生一样。

这正是 . 的返回值所发生的情况GetCursorPos。它提供逻辑像素而不是物理像素。

另一方面,鼠标钩子程序没有被系统调整。

我尝试在清单中将我的程序设置为不支持 DPI,如下所示:

<asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
    </asmv3:windowsSettings>
</asmv3:application>

但这没有什么区别。我还尝试将其声明为可识别 DPI,如下所示:

<asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        <dpiAware>True/PM</dpiAware>
    </asmv3:windowsSettings>
</asmv3:application>

这也没有任何区别。

是否有任何设置可以通过清单或其他方式添加到我的程序中,这将使鼠标钩子程序能够提供逻辑坐标GetCursorPos

我正在 Windows 10 中测试所有这些。


跟进:

我发现了问题。我的清单文件不正确。XML 命名空间未正确设置。

这是有效的。

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> 
    <assemblyIdentity version="1.0.0.0" name="AppName" type="win32"/>
    <asmv3:application>
        <asmv3:windowsSettings>
            <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
            <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>
</assembly>

为了让系统为程序提供逻辑坐标,程序必须是 DPI 感知的。没有表现出 DPI 感知能力的程序将处理不一致的坐标,不仅在鼠标钩子中,也在 BitBlt、IAccesibility、UIAutomation 等中。

我不明白为什么微软决定倒退。没有表现出 DPI 意识的程序应该像往常一样运行,而不是相反。

这意味着无论何时在监视器上设置缩放因子,大多数程序都会默认中断。为了破解它们,它们必须具有 DPI 意识,并且......就像那样......它们将再次工作。

4

1 回答 1

-1

我不明白为什么微软决定倒退。没有表现出 DPI 意识的程序应该像往常一样运行,而不是相反。

事实上,微软的文档解释了这个问题。

来自Windows 上的高 DPI 桌面应用程序开发

使用较旧的 Windows 编程技术(原始 Win32 编程、Windows 窗体、Windows Presentation Framework (WPF) 等)的桌面应用程序无法在没有额外开发人员工作的情况下自动处理 DPI 缩放。如果没有这样的工作,在许多常见的使用场景中,应用程序将显得模糊或大小不正确。

如果您想避免 DPI 感知问题,请创建一个UWP应用程序。

首先,如果您要从头开始创建新的 Windows 应用,强烈建议您创建通用 Windows 平台(UWP) 应用程序。UWP 应用程序自动且动态地针对它们运行的​​每个显示器进行缩放。

于 2020-06-22T05:32:54.927 回答