如何获得显示器的正确物理尺寸?

如何以厘米或英寸显示显示器的大小?

此代码并不总是正常工作:

HDC hdc = CreateDC(_T("DISPLAY"),dd.DeviceName,NULL,NULL); int width = GetDeviceCaps(hdc, HORZSIZE); int height = GetDeviceCaps(hdc, VERTSIZE); ReleaseDC(0, hdc) 

尤其适用于多显示器configuration。

更新:我需要得到的大小只是普通的显示器,其具有恒定的物理尺寸。

Solutions Collecting From Web of "如何获得显示器的正确物理尺寸?"

我找到了另一种方式。 监视器的物理大小存储在EDID中,Windows几乎总是在注册表中的值的副本。 如果您可以解析EDID,则可以以厘米为单位读取显示器的宽度和高度。

更新:添加代码

 BOOL GetMonitorDevice( TCHAR* adapterName, DISPLAY_DEVICE &ddMon ) { DWORD devMon = 0; while (EnumDisplayDevices(adapterName, devMon, &ddMon, 0)) { if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && ddMon.StateFlags & DISPLAY_DEVICE_ATTACHED) // for ATI, Windows XP break; devMon++; } if (ddMon.DeviceString[0] == '\0') { EnumDisplayDevices(adapterName, 0, &ddMon, 0); if (ddMon.DeviceString[0] == '\0') _tcscpy_s(ddMon.DeviceString, _T("Default Monitor")); } return ddMon.DeviceID[0] != '\0'; } BOOL GetMonitorSizeFromEDID(TCHAR* adapterName, DWORD& Width, DWORD& Height) { DISPLAY_DEVICE ddMon; ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); //read edid bool result = false; Width = 0; Height = 0; if (GetMonitorDevice(adapterName, ddMon)) { TCHAR model[8]; TCHAR* s = _tcschr(ddMon.DeviceID, '\\') + 1; size_t len = _tcschr(s, '\\') - s; if (len >= _countof(model)) len = _countof(model) - 1; _tcsncpy_s(model, s, len); TCHAR *path = _tcschr(ddMon.DeviceID, '\\') + 1; TCHAR str[MAX_PATH] = _T("SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\"); _tcsncat_s(str, path, _tcschr(path, '\\')-path); path = _tcschr(path, '\\') + 1; HKEY hKey; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, str, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD i = 0; DWORD size = MAX_PATH; FILETIME ft; while(RegEnumKeyEx(hKey, i, str, &size, NULL, NULL, NULL, &ft) == ERROR_SUCCESS) { HKEY hKey2; if(RegOpenKeyEx(hKey, str, 0, KEY_READ, &hKey2) == ERROR_SUCCESS) { size = MAX_PATH; if(RegQueryValueEx(hKey2, _T("Driver"), NULL, NULL, (LPBYTE)&str, &size) == ERROR_SUCCESS) { if (_tcscmp(str, path) == 0) { HKEY hKey3; if(RegOpenKeyEx(hKey2, _T("Device Parameters"), 0, KEY_READ, &hKey3) == ERROR_SUCCESS) { BYTE EDID[256]; size = 256; if(RegQueryValueEx(hKey3, _T("EDID"), NULL, NULL, (LPBYTE)&EDID, &size) == ERROR_SUCCESS) { DWORD p = 8; TCHAR model2[9]; char byte1 = EDID[p]; char byte2 = EDID[p+1]; model2[0]=((byte1 & 0x7C) >> 2) + 64; model2[1]=((byte1 & 3) << 3) + ((byte2 & 0xE0) >> 5) + 64; model2[2]=(byte2 & 0x1F) + 64; _stprintf(model2 + 3, _T("%X%X%X%X"), (EDID[p+3] & 0xf0) >> 4, EDID[p+3] & 0xf, (EDID[p+2] & 0xf0) >> 4, EDID[p+2] & 0x0f); if (_tcscmp(model, model2) == 0) { Width = EDID[22]; Height = EDID[21]; result = true; } else { // EDID incorrect } } RegCloseKey(hKey3); } } } RegCloseKey(hKey2); } i++; } RegCloseKey(hKey); } } return result; } 

不可能在窗口上确定视频设备的确切物理尺寸,因为这取决于相当多的变量(例如,活动的监视器配置文件,水平/垂直分辨率,像素尺寸等),其中一些不在电脑的控制。

以投影机设备为例,实际尺寸取决于投影区域的距离,而投影区域无法以编程方式确定,因为视频投影机可随时手动移动。

直接浏览注册表不仅是不受支持的,而且对于不同于您的设备而言实际上是失败的。 (例如,我测试你的代码的那个)。

不同于在这里说的一些,有一个官方的方式来访问EDID键路径:通过使用安装API,特别是SetupDiOpenDevRegKey 。

涉及一些繁琐的设置 – 示例代码在这里 。


编辑:多个显示器在这里处理。

你不能得到真正的大小 – 你可以得到一个近似值,取决于窗口中的DPI设置和屏幕的分辨率,但是你不能保证这是真实的大小。

特别是在具有不同显示器的多监视器情况下(例如19“CRT和24”LCD)。 而且,如果显示器是CRT,则测量是管测量,而不是显示区域。

当程序过去需要这些信息时,他们已经在屏幕上显示了一个量表,并且让用户拿着一张纸到屏幕上,用量表测量纸张的宽度。 如果纸张宽度为8.5英寸或A4,那么您就知道宽度,您可以使用输入的数字来计算给定显示器的实际DPI值。您可能需要让它们为多监视器设置中的每个监视器执行此操作。

-亚当

Windows Vista和上层支持新功能GetMonitorDisplayAreaSize() http://msdn.microsoft.com/en-us/library/ms775210%28VS.85%29.aspx

更新:它不能正常工作

您可以从GetDeviceCaps请求LOGPIXELSX来获取显示器的DPI,但它通常会返回96.另请参阅此MSDN有关编写DPI感知应用程序的文章 。

您可以从注册表中获取EDID。