标题: GetDeviceCaps函数的困惑
作者: Demon
链接: https://demon.tw/programming/getdevicecaps-function.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
关于GetDeviceCaps函数,《Windows程序设计》中有这样的文字:
Within a Windows program you can use the GetDeviceCaps function to obtain the assumed resolution in dots per inch that the user selected in the Display applet of the Control Panel. To get these values—which in theory could be different if the video display doesn’t have square pixels—you use the indices LOGPIXELSX and LOGPIXELSY. The name LOGPIXELS stands for "logical pixels," which basically means "not the actual resolution in pixels per inch."
The device capabilities that you obtain from GetDeviceCaps with the HORZSIZE and VERTSIZE indices are documented (as I indicated earlier) as "Width, in millimeters, of the physical screen" and "Height, in millimeters, of the physical screen." These should be documented as a "logical width" and a "logical height," because the values are derived from the HORZRES, VERTRES, LOGPIXELSX, and LOGPIXELSY values. The formulas are
Horizontal Size (mm) = 25.4 × Horizontal Resolution (pixels)/ Logical Pixels X (dots per inch)
Vertical Size (mm) = 25.4 × Vertical Resolution (pixels)/ Logical Pixels Y (dots per inch)
The 25.4 constant is necessary to convert from inches to millimeters.
This may seem backward and illogical. After all, your video display has a size in millimeters that you can actually measure with a ruler (at least approximately). But Windows 98 doesn’t care about that size. Instead it calculates a display size in millimeters based on the pixel size of the display the user selects and also the resolution the user selects for sizing the system font. Change the pixel size of your display and according to GetDeviceCaps the metrical size changes. How much sense does that make?
HORZSIZE和VERTSIZE并不像文档中写的那样是屏幕的物理宽度和物理高度,而是“逻辑宽度”和“逻辑高度”,因为它们的值是根据HORZRES、VERTRES、LOGPIXELSX、LOGPIXELSY通过计算得到的,公式如下:
HORZSIZE = 25.4 * HORZRES / LOGPIXELSX
VERTSIZE = 25.4 * VERTRES / LOGPIXELSY
问题在于这个公式是Windows 98下的公式,对于现在的系统似乎并不成立,测试程序如下:
#include <stdio.h> #include <Windows.h> /************************************************************************/ /* By Demon */ /* https://demon.tw */ /************************************************************************/ int main() { HDC hdc = GetDC(NULL); int x_size, y_size, x_res, y_res, x_dpi, y_dpi; x_size = GetDeviceCaps(hdc, HORZSIZE); y_size = GetDeviceCaps(hdc, VERTSIZE); x_res = GetDeviceCaps(hdc, HORZRES); y_res = GetDeviceCaps(hdc, VERTRES); x_dpi = GetDeviceCaps(hdc, LOGPIXELSX); y_dpi = GetDeviceCaps(hdc, LOGPIXELSY); printf( "HORZSIZE: %d\n" "VERTSIZE: %d\n" "HORZRES: %d\n" "VERTRES: %d\n" "LOGPIXELSX: %d\n" "LOGPIXELSY: %d\n", x_size, y_size, x_res, y_res, x_dpi, y_dpi); return 0; }
在Windows 7系统中测试,当分辨率为1280 × 800,DPI为96时,输出:
HORZSIZE: 452 VERTSIZE: 282 HORZRES: 1280 VERTRES: 800 LOGPIXELSX: 96 LOGPIXELSY: 96
保持分辨率不变,将DPI改为120,输出:
HORZSIZE: 452 VERTSIZE: 282 HORZRES: 1280 VERTRES: 800 LOGPIXELSX: 120 LOGPIXELSY: 120
LOGPIXELSX和LOGPIXELSY改变了,但是HORZSIZE和VERTSIZE并没有改变。
保持DPI不变,将分辨率改为800 × 600,输出:
HORZSIZE: 282 VERTSIZE: 212 HORZRES: 800 VERTRES: 600 LOGPIXELSX: 120 LOGPIXELSY: 120
说明HORZSIZE和VERTSIZE只跟HORZRES和VERTRES有关,与LOGPIXELSX和LOGPIXELSY无关;或者说与分辨率有关,与DPI无关。
经过观察可以发现计算公式:
HORZSIZE = 25.4 * HORZRES / 72
VERTSIZE = 25.4 * VERTRES / 72
也就是原公式中的LOGPIXELSX和LOGPIXELSY变成了固定值72,至于为什么,只有微软才知道。
查了一下《Windows程序设计》第五版是1998年12月出版的,所以内容一直都没有针对新的系统更新过。虽然今年初出版了《Windows程序设计》第六版,但是开发语言使用的是C#而不是C了。
赞赏微信赞赏支付宝赞赏
随机文章:
M$ 的东西就是这样的……M$ 以外的人永远不会知道这个东西到底是怎么实现的,其充量就是做一些黑箱分析。
这个关系也不成立。72是每英寸72磅,也是逻辑点的意思,它不是像素点。