如何以厘米或英寸为单位显示显示尺寸?
此代码并不总是正常工作:
HDC hdc = CreateDC(_T("DISPLAY"),dd.DeviceName,NULL,NULL); int width = GetDeviceCaps(hdc, HORZSIZE); int height = GetDeviceCaps(hdc, VERTSIZE); ReleaseDC(0, hdc)
特别适用于多显示器配置.
更新:我需要获得普通显示器的大小,它具有恒定的物理尺寸.
我发现了另一种方式.监视器的物理大小存储在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; }
在Windows上无法确定视频设备的确切物理尺寸,因为这取决于相当多的变量(例如,有源监视器配置文件,水平/垂直分辨率,像素大小等),其中一些不在控制计算机.
想想投影仪设备的例子,其中物理尺寸取决于到投影区域的距离,这是无法以编程方式确定的,因为视频投影仪可以随时手动移动.
直接导航注册表不仅不受支持,而且对于与您不同的设备实际上也会失败.(例如,我测试你的代码的那个).
不像有些什么在这里说,有是访问EDID关键路径的官方途径:通过使用安装程序的API,特别SetupDiOpenDevRegKey.
这涉及一些繁琐的设置 - 示例代码在这里.
编辑:这里处理多个监视器.
您无法获得真正的确切大小 - 您可以获得取决于窗口中DPI设置的近似值以及屏幕的分辨率,但您无法保证这是实际大小.
特别是在具有不同显示器的多监视器情况下(例如19"CRT和24"LCD).此外,如果显示器是CRT,则测量是管测量,而不是显示区域.
当程序在过去完全需要这些信息时,他们在屏幕上显示了一个仪表,并让用户将一张纸拿到屏幕上并用仪表测量纸张宽度.如果纸张是8.5英寸或A4,那么您就知道宽度,并且您可以使用它们输入的数字来计算给定显示器的实际DPI.您可能需要让它们在多监视器设置中为每个监视器执行此操作.
-亚当