winapi - 设置进程 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%,鼠标钩总是给我物理像素。
另一方面,GetCursorPos
winapi 函数以逻辑像素给出坐标。即如果缩放因子为200%,GetCursorPos
将给出除以2的坐标,而鼠标钩将给出未调整的数字。
如果程序不支持 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 意识,并且......就像那样......它们将再次工作。
解决方案
我不明白为什么微软决定倒退。没有表现出 DPI 意识的程序应该像往常一样运行,而不是相反。
事实上,微软的文档解释了这个问题。
使用较旧的 Windows 编程技术(原始 Win32 编程、Windows 窗体、Windows Presentation Framework (WPF) 等)的桌面应用程序无法在没有额外开发人员工作的情况下自动处理 DPI 缩放。如果没有这样的工作,在许多常见的使用场景中,应用程序将显得模糊或大小不正确。
如果您想避免 DPI 感知问题,请创建一个UWP
应用程序。
首先,如果您要从头开始创建新的 Windows 应用,强烈建议您创建通用 Windows 平台(UWP) 应用程序。UWP 应用程序自动且动态地针对它们运行的每个显示器进行缩放。
推荐阅读
- javascript - 无法使用 jQuery 获取图像的 src
- c++ - wxWidgets - 将数据添加到 DataViewListCtrl
- python - css 显示:块在烧瓶上不起作用?
- javascript - 摩卡单元测试:未捕获的类型错误:无法读取未定义的属性“应用”
- php - PHP 单元测试 - 测试方法返回生成器
- word-embedding - 在本地下载预训练的句子转换器模型
- react-native - 返回 VersionCheck.getLatestVersion() 结果为字符串
- azure-storage - 无法将 VHD 文件上传到 Azure 存储
- java - Java 中“Mark & Sweep”的行为,尤其是对于 Future 对象
- linux - linux bash保存的变量为空