如何确保应用程序在高 DPI 显示器上正确显示

尽管 DirectWrite 可解决许多高 DPI 问题,但应采取两个步骤来确保应用程序在高 DPI 显示器上正常工作。

步骤 1:创建窗口后使用窗口自己的 DPI

这可以通过使用 Direct2D 或使用 GDI 来完成。

Direct2D

GetDpiForWindow 函数检索指定窗口的每英寸点数 (dpi) 值。 若要使用该值设置窗口的宽度,请使用以下公式:

< Dpi> * <宽度,以像素> 为单位/ <默认 DPI>

...其中 DPIGetDpiForWindow 重新尝试的值, 默认 DPI 为 96。 垂直轴的公式类似:

< Dpi> * <高度,以像素> 为单位/ <默认垂直 DPI>

创建简单 Direct2D 应用程序的步骤 2.3 中的代码示例检索窗口的 DPI,然后将其大小设置为 640 × 480,缩放到 DPI。

注意

对于通用 Windows 平台 (UWP) 应用,可以使用 DisplayInformation::LogicalDpi 属性。

GDI

GDI 提供 GetDeviceCaps 函数用于检索设备信息。 可以通过传递 LOGPIXELSXLOGPIXELSY 索引值来检索 DPI 信息。 用于确定窗口的水平和垂直大小的公式与上面的 Direct2D 示例相同。

以下代码使用 GetDeviceCaps 函数创建一个缩放为系统 DPI 的 640 x 480 窗口。

FLOAT dpiX, dpiY;

HDC screen = GetDC(0);
dpiX = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSX));
dpiY = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSY));
ReleaseDC(0, screen);

hWnd = CreateWindow(
    TEXT("DirectWriteApp"),
    TEXT("DirectWrite Demo App"),
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    static_cast<INT>(dpiX * 640.f / 96.f),
    static_cast<INT>(dpiY * 480.f / 96.f),
    NULL,
    NULL,
    hInstance,
    NULL);

步骤 2:声明应用程序可感知 DPI

当应用程序声明自己为 DPI 感知时,它是一个语句,指定应用程序在高达 200 DPI 的 DPI 设置下表现良好。 在 Windows Vista 和 Windows 7 中,启用 DPI 虚拟化后,将缩放不感知 DPI 的应用程序,应用程序将从系统 API(如 GetSystemMetric 函数)接收虚拟化数据。 若要声明应用程序可识别 DPI,请完成以下步骤。

  1. 创建名为 DeclareDPIAware.manifest 的文件。

  2. 将以下 xml 复制到 文件中并保存:

    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
      <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
          <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
      </asmv3:application>
    </assembly>
    
  3. 在项目的 .vcproj 文件中,在 VisualStudioProject/Configurations 下的每个 Configuration 元素中添加以下条目:

    <Tool
        Name="VCManifestTool"
        AdditionalManifestFiles="DeclareDPIAware.manifest"/>