如何创建与 Windows 7 向后兼容的缩放和大小更改的 Per-Monitor DPI 感知应用程序?
Posted
技术标签:
【中文标题】如何创建与 Windows 7 向后兼容的缩放和大小更改的 Per-Monitor DPI 感知应用程序?【英文标题】:How to create a scaling and size-changing Per-Monitor DPI-aware application that is backwards compatible with Windows 7? 【发布时间】:2015-11-12 18:27:40 【问题描述】:我是 WPF(以及 DPI 感知 API)的新手,正在编写一个在 Windows 7、8.1 和 10 中运行的应用程序。我使用具有不同每个显示器 DPI 设置的多个显示器,并且有兴趣制作我的应用程序尽可能跨桌面配置兼容。
我已经知道可以将 Manifest 添加到 WPF 应用程序,取消注释 DPI 感知部分,并将其设置为 True/PM
。这成功地允许程序在 Windows 8.1 和 10 中支持 Per-Monitor DPI(因此在各种显示器上看起来干净而清晰),但在 Windows 7 中作为系统感知运行。
但是我们可以做得更好吗?
Microsoft 提供了一个neat tutorial here that shows how to create a Per-Monitor DPI-Aware WPF 应用程序。
他们所做的实际上是在 C++ 中创建一个新对象来替换 <Window>
,该对象使用 Windows 8.1 API 不仅可以检测监视器之间的 DPI 变化,还可以在运行时重新调整应用程序的大小,有效匹配 DPI 的变化。
最终结果是,不仅应用程序 Per-DPI 感知和清晰的外观,而且当在各种尺寸的大型和小型显示器之间切换时,应用程序会要求用户更改屏幕上相同的物理尺寸(以英寸或厘米为单位) .
微软的 Win32 代码的缺点是它不能向后兼容 Windows 7。尝试在 7 中运行会导致应用程序崩溃。
我已经使用了 this article on Dr.Dobbs 和 this one by Kenny Karr,但对 API 的理解不足以让事情顺利进行。
有没有人知道一种类似于 Microsoft 代码的方法,在 Windows 8.1 和更新版本中,每个监视器感知的应用程序实际上会在监视器之间移动时更改大小,但运行作为 Windows 7 中的系统感知功能?
【问题讨论】:
【参考方案1】:我没有看代码,但我的猜测是崩溃是因为在win 7中缺少原生方法造成的。 解决这个问题的方法是修改原生方法包装器,例如(伪代码):
public int GetDPIOfMonitor(IntPtr monitorHandle)
if (Enviroment.OSVersion >= "6.2") // win 8 and above
return NativeMethods.PInvoke.GetMonitorDPI(monitorHandle);
else return systemDPI;
这样你就不会在 7 下崩溃,因为你没有调用缺少的本地方法。
【讨论】:
我已经有一段时间没有解决这个问题了,但我学到了更多……我相信你的解决方案在运行时会失败。我的理论是,当应用程序进入public int GetDPIOfMonitor(IntPtr monitorHandle)
时,CLR 将尝试将 NativeMethods
加载到内存中,这仍然会导致 Windows 7 崩溃。解决此问题的一种方法是将 return NativeMethods.PInvoke.GetMonitorDPI(monitorHandle);
本身放入另一种方法中,这意味着如果 if 语句失败,CLR 将不会加载必要的代码。我想同时测试一下。
emoacht 一直在开发library that can handle a lot of this work and runs on Windows 7 and up。我没有使用它,因为我目前对 Window Chrome 的理解不够好,无法将它与 FluentRibbon 等库结合起来。
@ohioDeveloper - 你错了。这不是 p/invoke 的工作方式。 p/invoke 只是一个字符串定义。这是完全任意的。只有在您实际调用 p/invoke 方法时才会检查其有效性。因此,您可以在您的应用程序中为各种事物提供 p/invoke 定义,即使它们不存在也没关系。我开发了必须在 XP 和 7 中运行的应用程序。当然,XP 不包含 7 所具有的本机方法。使用上述伪代码完美运行,没有失败。
@ohioDeveloper:您也可以简单地trycatch(DllNotFoundException)
来检查缺少的 PInvoke 方法。以上是关于如何创建与 Windows 7 向后兼容的缩放和大小更改的 Per-Monitor DPI 感知应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
Windows:如何解决缺少的过程入口点以实现向后兼容性? [复制]
Xcode 7 Stack Views 如何向后兼容 iOS 8 和 iOS 7?