在Windows下获取实际屏幕dpi/ppi

And*_* Li 19 c++ windows screen dpi ppi

我想获得实际的屏幕dpi/ppi,而不是C++中用于字体的dpi设置.

我尝试使用以下代码:

版本1,报告72 dpi,这是错误的.

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hSize = GetDeviceCaps(screen, HORZSIZE);
double vSize = GetDeviceCaps(screen, VERTSIZE);
double hRes = GetDeviceCaps(screen, HORZRES);
double vRes = GetDeviceCaps(screen, VERTRES);
double hPixelsPerInch = hRes / hSize * 25.4;
double vPixelsPerInch = vRes / vSize * 25.4;
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;
Run Code Online (Sandbox Code Playgroud)

版本2,报告96 dpi,这是字体的Windows dpi设置,但不是实际的屏幕dpi.

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
double vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;
Run Code Online (Sandbox Code Playgroud)

Adr*_*thy 13

不幸的是,在一般情况下,你所要求的是不可能的.

Windows不知道物理屏幕大小.Windows可能知道您的屏幕有1024x768像素,但它不知道屏幕实际有多大.您可以将电缆拉出旧的13英寸屏幕并将其连接到19英寸显示器而不更改分辨率.DPI会有所不同,但Windows不会注意到您更改了监视器.

您可以获得打印机的真实物理尺寸和DPI(假设驱动程序没有说谎),但不能用于屏幕.至少不可靠.

更新

正如其他人所指出的那样,新的监视器和操作系统(EDID)之间存在双向通信的标准,这可能使这些信息可用于某些设备.但我还没有找到提供此信息的显示器.

即使EDID是普遍可用的,在一般情况下仍然无法解决,因为显示器可能是视频投影仪,其中DPI将取决于变焦,焦距,镜头类型和投射距离.投影机极不可能知道投射距离,因此无法报告实际的DPI.

  • @leetNightshade:Ian是对的,Windows开发人员并不关心_physical_ DPI.他们必须关心_logical_ DPI.不幸的是,Windows让太多的开发人员忽视它太长时间了,所以现在解决方案已经有了很大的进步,我们都很痛苦. (4认同)
  • @Ian Boyd`幸运的是,作为Windows开发人员,您不必关心显示器的物理分辨率.随着4K显示器的出现,事实证明并非如此.人们发现Windows + 4K并不是非常有用,因为大多数程序都不能很好地处理DPI增长.即使使用Windows扩展功能也无法全面发挥作用.我希望事情能够得到解决,因为有人渴望获得4K显示器. (3认同)
  • @leetNightshade作为Windows开发人员,自20世纪80年代以来,您应该一直在做Web开发人员正在学习的内容.在网络上,你应该在`em`或`en`中指定图像,按钮,文本框等的大小.这样你就不关心显示器的分辨率了.几十年来,Windows使用了等效的`em`:**对话框**(基于你正在使用的字体中平均字符的宽度和高度). (3认同)
  • 争取正确答案。Windows不知道显示器的物理尺寸。它所知道的只是“ 1680x1050”。它不知道是22英寸显示器(90dpi),21英寸显示器(94dpi),20英寸显示器(99dpi)还是4英寸掌上电脑(495dpi)。幸运的是,作为Windows开发人员,您不必关心显示器的物理分辨率。 (2认同)
  • [来自USERMODE的驱动程序查询的EDID](http://stackoverflow.com/questions/577736/how-to-obtain-the-correct-physical-size-of-the-monitor) (2认同)
  • 现在是 2017 年,了解典型屏幕(即非投影仪)的物理尺寸对于许多 UI/UX 设计师来说是重要信息。如果您希望图标具有一定的物理尺寸,那么了解逻辑 dpi 有什么用呢? (2认同)

Kat*_*age 7

老实说,我对这里的答案感到困惑。

Microsoft有一个GetDpiForMonitor方法:

https://msdn.microsoft.com/zh-CN/library/windows/desktop/dn280510(v=vs.85).aspx

监视器确实会将其物理尺寸暴露给工具。您可以使用HWiNFO64工具以厘米为单位读取显示器的宽度和高度。因此,如果他们得到它(DDI?),则可以说您可以自己访问该信息。

甚至另一个不同的Stack Overflow帖子都提到使用WmiMonitorBasicDisplayParams来获取数据。

如何获得显示器尺寸

因此,最热门的帖子是100%错误的。

  • GetDpiForMonitor为您提供每逻辑英寸而不是物理英寸的点数。一些监视器通过EDID公开其物理尺寸。不幸的是,这不是普遍可用的。许多显示器不支持它。WmiMonitorBasicDisplayParams的文档的“备注”部分指出,实际值可能不可用。另外,显示器可能是投影仪,并且投影仪无法知道投影距离,因此即使知道缩放设置也无法计算物理尺寸。在所有情况下都没有可靠的方法来获取实际的DPI。抱歉。 (3认同)
  • 使用MDT_RAW_DPI调用的GetDpiForMonitor确实会返回实际的物理DPI(如果明显可用)。在我的机器上,`MDT_EFFECTIVE_DPI` =(144,144),`MDT_RAW_DPI` =(158,160)。 (2认同)