首页 > 解决方案 > 设置进程 DPI 感知,以便系统补偿缩放因子

问题描述

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

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 意识,并且......就像那样......它们将再次工作。

标签: winapiwindows-10mouse-hookmouse-coordinatesdpi-aware

解决方案


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

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

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

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

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

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


推荐阅读