如何以厘米或英寸为单位显示显示尺寸?
此代码并不总能正常运行:
HDC hdc = CreateDC(_T("DISPLAY"),dd.DeviceName,NULL,NULL);
int width = GetDeviceCaps(hdc, HORZSIZE);
int height = GetDeviceCaps(hdc, VERTSIZE);
ReleaseDC(0, hdc)
特别适用于多显示器配置。
更新:我需要获得普通显示器的尺寸,这些显示器具有恒定的物理尺寸。
答案 0 :(得分:18)
我发现了另一种方式。监视器的物理大小存储在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;
}
答案 1 :(得分:8)
无法确定Windows上视频设备的确切物理尺寸,因为这取决于很多变量(例如,有源监视器配置文件,水平/垂直分辨率,像素大小等),其中一些是不受电脑控制。
想想投影仪设备的例子,其中物理尺寸取决于到投影区域的距离,这是无法以编程方式确定的,因为视频投影仪可以随时手动移动。
答案 2 :(得分:6)
直接导航注册表不仅不受支持,而且对于与您不同的设备实际上也失败了。 (例如,我测试你的代码的那个)。
与此处所说的不同, 是访问EDID密钥路径的官方方式:使用Setup API,特别是SetupDiOpenDevRegKey。
涉及一些繁琐的设置 - Sample code is here。
编辑:处理多个监视器here。
答案 3 :(得分:5)
你无法获得真正的确切大小 - 你可以得到一个取决于窗口中DPI设置的近似值,以及屏幕的分辨率,但你不能保证这是真正的大小。
特别是在具有不同显示器的多监视器情况下(例如19“CRT和24”LCD)。此外,如果显示器是CRT,则测量是管测量,而不是显示区域。
当程序在过去完全需要这些信息时,他们在屏幕上显示了一个仪表,并让用户将一张纸拿到屏幕上并用仪表测量纸张宽度。如果纸张是8.5“或A4,那么您就知道宽度,并且您可以使用它们输入的数字来计算给定显示器的实际DPI。您可能需要让它们在多监视器设置中为每个监视器执行此操作。
- 亚当
答案 4 :(得分:4)
Windows Vista和上层支持新功能GetMonitorDisplayAreaSize() http://msdn.microsoft.com/en-us/library/ms775210%28VS.85%29.aspx
更新:它无法正常工作
答案 5 :(得分:2)
您可以从GetDeviceCaps请求LOGPIXELSX获取显示的DPI,但通常会返回96.另请参阅此MSDN article on writing DPI-aware apps。
答案 6 :(得分:0)
您可以从注册表中获取EDID。