如何以编程方式确定Windows DPI设置?

3
我们的一个非DPI感知的MFC应用程序存在问题。
如果您将系统设置更改为高DPI(例如120或144 DPI),则任务栏上的应用程序图标看起来很糟糕。不幸的是,我们必须为主窗体注册自己的WNDCLASS,并且在WNDCLASS.hIcon成员中必须设置一个图标。该图标使用LoadIcon函数加载。该函数尝试以标准大小加载图像(与GetSystemMetrics(SM_CXICON)返回的大小相同),对于120dpi而言,该大小为40x40像素。这很不幸,因为我们没有提供该大小的图标。但是有一种解决方法:由于奇怪的是,dpi虚拟化似乎对120 dpi无效,GetDeviceCaps(...,LOGPIXELSX)确实返回120 dpi,并且GetSystemMetrics(SM_CXICON)返回40。因此,我们可以捕获它并只是以不同的大小加载图标。但对于144 dpi,它不起作用,因为现在虚拟化似乎已经生效,我们得到96 dpi和32像素,这再次导致图标看起来非常丑陋。
我发现如果我只是将WNDCLASS.hIcon成员设置为NULL,则图标会正常显示。但我想知道这样做是否可以,因为根据MSDN的说法:

hIcon
类图标的句柄。此成员必须是图标资源的句柄。如果此成员为NULL,则系统提供默认图标。

那么,即使我将该成员设置为NULL,我能保证图标总是显示吗?另一种方法是以正确的大小加载图标,但为此,我必须知道系统实际上设置为144 dpi。这就是我最初的问题所在。有没有人知道是否可以确定系统的DPI设置(从dpi虚拟化应用程序内部)?请注意,我也考虑过执行一些不好的操作,例如让DPI感知应用程序告诉我实际DPI等内容,但如果可能的话,我要避免这些操作。
此致
humbagumba
更新:
我发现将WNDCLASS.hIcon成员设置为NULL并不是一个好主意,因为这样会替换主窗体的图标为默认图标(即使任务栏上看起来很好...)- 我在第一次测试时没有注意到这一点。
1个回答

5

您需要为程序添加清单(或编辑现有的清单),以关闭 DPI 虚拟化。清单应该如下所示:

<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>

这很可能会引起许多新问题。关于此,您想了解的一切都在这篇MSDN Library文章中得到很好的解释。


谢谢,但我已经试过了。这不是我正在寻找的,因为启用dpi感知会导致太多问题,特别是在144dpi下。你知道为什么应用程序在120dpi时表现得像是dpi感知一样(例如没有虚拟化,因此没有xp样式缩放)吗?该文章也没有提到是否有可能知道系统的实际DPI设置(而不启用dpi感知)。 - humbagumba
1
DPI 虚拟化直到 DPI 超过 120 才会启动。要找到真正的 DPI,需要关闭虚拟化。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接