设置过程DPI意识,以便系统补偿缩放因子

时间:2020-06-21 13:45:04

标签: winapi windows-10 mouse-hook mouse-coordinates dpi-aware

我有以下鼠标挂钩程序(为简化说明)。

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%,鼠标钩总是为我提供物理像素。

另一方面,GetCursorPos winapi函数以逻辑像素为单位给出坐标。即,如果缩放比例为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意识,并且……就这样……它们将再次起作用。

1 个答案:

答案 0 :(得分:-1)

我不明白为什么Microsoft决定倒退。不能表现DPI意识的程序应表现正常,而不是相反。

实际上,Microsoft的文档解释了此问题。

High DPI Desktop Application Development on Windows

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

如果要避免DPI意识问题,请创建一个UWP应用程序。

首先,如果要从头开始创建新的Windows应用程序, 强烈建议您创建一个Universal Windows Platform(UWP) 应用。 UWP应用程序可以自动,动态地扩展以适应 他们正在运行的每个显示器。

相关问题