使Windows通用对话框“支持每个显示器的DPI感知”。

8
我有一个在VS2008中用MFC创建的程序。 现在我已经修改它,使其成为“适应每个显示器DPI”,并且几乎完成了。我修改了清单并处理了WM_DPICHANGE消息。但是还有一个问题:
我使用CFileDialog类来显示打开/保存对话框,并使用SHBrowseForFolder函数来显示文件夹选择对话框。但是所有这些对话框都不是“适应每个显示器DPI”,当您将它们移动到具有不同DPI设置的显示器之间时,它们不会调整其UI。
我使用spy ++来监视这些对话框的消息,发现它们可以接收WM_DPICHANGED消息,但它们只是不处理它。
我已经在Windows 10上测试了记事本中的打开文件对话框,它完美地工作。
有人知道如何使这些对话框“适应每个显示器DPI”吗?
--------编辑--------
还有两个问题:
1.当我将窗口移动到具有不同DPI的监视器上时,窗口会自动调整大小,但其标题栏高度和标题字体大小没有更改。 2.复选框控件的框大小也没有更改。
我觉得这些问题可能有某种联系,但我无法弄清楚。
--------坏消息--------
我用VS2013编译了微软的“DPI教程示例”,它也有同样的问题。

https://code.msdn.microsoft.com/DPI-Tutorial-sample-64134744


1
通常情况下,你不会这样做。你正在使用的那些对话框已经过时了。对于打开/保存/浏览文件夹,现在应该使用公共项目对话框,具体来说是IFileOpenDialog。这些在Windows Vista及更高版本上可用,并且应该已经支持DPI感知。在较旧的操作系统上回退到旧的对话框。 - Cody Gray
1
顺便提一下,从VS2012(或者VS2010不太确定)开始,CFileDialog会自动使用通用项目对话框,无需任何额外的工作。 - Jabberwocky
@Michael Walz 实际上,在VS2008中,如果您在Windows Vista或更高版本上运行并将bVistaStyle设置为TRUE,则CFileDialog也会使用IFileDialog。(bVistaStyle默认设置为TRUE)[链接]https://msdn.microsoft.com/en-us/library/wh5hz49d.aspx - Caspar Lee
嗯,好的。我很惊讶他们一直在更新MFC。不错。那我就不知道了。你不应该在自己的代码中做任何事情来使内置的公共对话框工作。可能只是因为DPI支持在那里出了问题,就像Windows中的许多地方一样。不幸的是,我没有一个有不同DPI的监视器的系统,所以我不能为你检查它。 - Cody Gray
我非常确定你发现的问题是Windows的限制,没有(受支持的)方法可以修复它。即使是IFileDialog也无法工作。请注意,记事本不是每个监视器DPI感知,因此DPI虚拟化会启动并“使其工作”。您可以在Internet Explorer中注意到相同的问题,它是每个监视器DPI感知的。 - James Johnston
显示剩余2条评论
2个回答

1

标题栏(标题栏)可以通过调用EnableNonClientDpiScaling来进行缩放,该函数可在Windows版本> = Windows 10周年更新(1607)中使用。

如果您想要DPI缩放一个不支持单独监视器DPI缩放的旧对话框,可以使用SetThreadDpiAwarenessContext(与DPI_AWARENESS_CONTEXT_SYSTEM_AWARE或DPI_AWARENESS_CONTEXT_UNAWARE一起使用),使对话框的顶级窗口由Windows进行缩放。对话框可能会模糊,但至少大小是正确的(仅适用于> = 1607版本的Windows 10)。使用模式是在打开对话框之前调用此API,然后立即在调用API后恢复先前的DPI上下文。


0
根据 MSDN的说明,处理WM_DPICHANGED消息的窗口应该返回0。然而,任何发送WM_DPICHANGED的MFC窗口或控件将返回0,因为它们调用未知消息的默认窗口过程。
因此,通过测试窗口的LRESULT返回值是否等于零来判断某个窗口是否处理WM_DPICHANGED消息并不准确。
在跨不同DPI监视器移动时,仅适用于每个监视器DPI感知应用程序的窗口标题栏才会缩放,如 MSDN所述。不幸的是,窗口的非客户区永远不会调整DPI。

计算器和其他支持每个显示器 DPI 的 Windows 本地应用程序具有自定义标题栏绘制功能,如此处所述。


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