【问题标题】:C++ Windows API - How to retrieve font scaling percentage on Windows 10C++ Windows API - 如何在 Windows 10 上检索字体缩放百分比
【发布时间】:2021-05-15 13:37:09
【问题描述】:

我的目标是能够在 C++ 应用程序运行时根据显示器分辨率调整字体大小。

this question中解释了如何获取字体缩放百分比,但建议的功能GetScaleFactorForMonitor需要Windows 8.1。我的 C++ 应用程序必须在 Windows 7 或更高版本上运行。我已经尝试了几种基于获取设备上限参数比率的建议解决方案,但它们都在 Windows 10 系统上获得 1.0,其中 Windows“让一切都变大”设置为 150%。

根据 MS 文档,Visual Studio 正在向清单中添加“dpiAware”(这是我可以更改的设置)。可能是因为应用程序是在 Windows 7 系统上构建的,VS 生成的清单不包括 Windows 10 作为支持的操作系统。如果我添加行

       <!--This Id value indicates the application supports Windows 10, Windows Server 2016 and Windows Server 2019-->
      <supportedOS Id="{{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>

在清单中,当我在 Windows 10 上运行应用程序时,我收到“并排”错误。

如何在 Windows 7 或 10 系统上获得“让一切变大”和“让文本变大”设置?

构建系统:64 位 Windows 7、Visual Studio 2019 16.7.7 运行系统:Windows 7 或更高版本

【问题讨论】:

  • 阅读您的问题我不完全相信您阅读了您正确链接的帖子(或者也许我没有阅读正确?)。 “让一切变得更大”是“DPI 设置”(历史上设置为 100% - 96 dpi;125% - 120 dpi;150 % - 144 dpi;这是使用 HDC 的 dpi 值访问的。GetScaleFactorForMonitor 似乎是与此设置相关联,但我不知道您为什么要使用该功能而不是使用 DPI 值)。 “使文本变大”似乎是“新”的 WinRT 事物(因此在 Windows 7 中不存在),并使用UISettings.TextScaleFactor 阅读。
  • 我需要我的应用调整字体大小以匹配用户的设置。正如您所指出的,在 Win 7 中,只有选项 100、125 和 150%。在 Win 10(也许还有 Win 8.1,不要在意;没有人会使用 8 或 8.1)中,有两种设置。无论哪种情况,我都需要知道所需的字体大小(以像素为单位),它与显示器的 dpi 不同。例如,在 3840x2160 显示器上,我将“让一切变大”设置为 150%,正确的外观是通过将字体大小(高度)乘以 1.5 获得的。但是如何获得用户设置的 1.5 因子? (续)
  • (conti) TextScaleFactor 是 .NET 的东西,我只使用 MFC。
  • > For example, on a 3840x2160 monitor, I have the "make everything bigger" set to 150%... "让一切变得更大" DPI 设置。您混淆了这两个设置。 TextScaleFactor(即“使文本变大”)不是 .NET 的东西,而是 WinRT 的东西。这主要用于 UWP 开发,适用于 .NET 和 C++(通过 C++/WinRT);它适用于 UWP 应用程序,而不是 Win32 应用程序(当然,尽管没有人阻止您在 Win32 应用程序中使用它,但您必须调用 WinRT 库,或读取未记录的注册表项)。
  • DPI 是每英寸点数的缩写,通常指显示器上的显示。确实,这可以在硬件中或通过 WINdows 进行更改,但事实并非如此。 Windows 通过使用不同的字体和控件等大小来调整所有内容的大小,但显示屏以每物理英寸的相同点数(像素)显示这些内容。所以问题仍然存在:我怎样才能访问用户设置的 1.5 比例因子。

标签: c++ manifest text-size


【解决方案1】:

在 cmets 中讨论后,事实证明您的实际问题是您没有在清单中正确声明 DPI 意识。

您需要将其合并到您的清单中

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
    </windowsSettings>
  </application>
</assembly>

解释:

dpiAwaretrue 被 Windows 7Windows 10 识别,并声明系统范围的 DPI 感知 (DPI_AWARENESS_SYSTEM_AWARE)。系统范围意味着它假定所有显示器上的所有应用程序都使用相同的 DPI 设置。

dpiAwareness 可被 Windows 10 识别(Windows 7 会忽略它),如果存在,则会取代 dpiAware。它声明了每个显示器的 DPI 感知 (DPI_AWARENESS_PER_MONITOR_AWARE),这意味着每个显示器可以有不同的 DPI 设置,您的应用程序必须正确处理。(2)

如果您不包含此清单,Windows 将虚拟化 DPI,这意味着它会就好像 DPI 设置始终为 96 (100%),并且然后 Windows 只是缩放位图(模糊)。这是一种兼容性措施,可确保未实现 DPI 代码的应用程序仍然可以显得更大。


然后,在 Windows 7 上,您可以使用带有 LOGPIXELSXLOGPIXELSYGetDeviceCaps 函数获得缩放因子,然后将结果除以 96(因为 96 dpi 是“ 100%")。(1) 这将为您提供主显示器的 DPI 设置。自 Windows XP 以来,GetDeviceCaps 一直是获取此设置的方法。这也将在 Windows 10 上运行良好当且仅当声明 DPI 感知每个显示器

在 Windows 10 上,如果您声明 DPI 感知每台显示器GetDeviceCaps足够,因为它只返回主显示的 DPI 设置。但是,如果您声明PerMonitorV2,那么您有义务正确实施每个显示器的 DPI。为此,您可以致电GetDpiForWindow,或MonitorFromWindow + GetDpiForMonitor

由于您希望您的可执行文件同时在 Windows 7 和 Windows 10 上运行,因此您不能链接到 GetDpiForWindowGetDpiForMonitor,因为这些函数在 Windows 7 中不存在。您需要在运行时使用手动链接GetProcAddress.


要合并清单,您可以使用 Visual Studio 中的清单工具(项目属性 -> 清单工具)。将上面的整个清单 XML 文本放入一个文件(例如 DpiAwareness.manifest),并在 Manifest Tool -> Input and Output -> Additional Manifest 下指定文件


至于“使文本变大”辅助功能设置:这是一个相对较新的 WinRT 设置,适用于 UWP 应用。您实际上并不希望在 Win32 应用程序中使用它,因此在 Win32 中它会变得很尴尬。我无法帮助你,因为我讨厌 UWP 的所有东西。 UWP 可能会死于火灾。


(1) 不过,我从未见过具有非1:1 纵横比的DISPLAY 设备。它可能只对打印机有用。 GetDpiForWindow 是提到的最现代的函数,仅返回一个数字这一事实表明,假设 X 方向的 DPI 将始终等于 Y 方向的 DPI 可能是安全的(在 @987654345 @ 设备)。

(2) 注意还有dpiAwarenessPerMonitor(没有V2)。这或多或少是 Windows 8 附带的一个现已过时的 hack。不要理会它。

【讨论】:

  • 事实证明我的清单没有任何问题。 VS 默认添加 dpiAware=true ,我在最后的评论中验证了我的清单包含它。现在使用的是来自GetDeviceCaps 的值,如您的示例soln (现在似乎已从GitHub 中消失),它运行良好。非常感谢您的耐心帮助和解释。
  • @Woody20 VS 不会自动添加 DPI 感知。也许您设置了 Manifest Tool -> 输入和输出 -> DPI 感知。该设置可以将两个标签之一添加到清单中,但不能同时添加。我发现该设置相当复杂和隐藏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-02
  • 2016-09-08
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
  • 2015-11-13
相关资源
最近更新 更多