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

C 如何获得正确的显示器物理尺寸?,c,windows,winapi,monitor,C,Windows,Winapi,Monitor,如何获得显示器的尺寸(厘米或英寸) 此代码并不总是正常工作: HDC hdc = CreateDC(_T("DISPLAY"),dd.DeviceName,NULL,NULL); int width = GetDeviceCaps(hdc, HORZSIZE); int height = GetDeviceCaps(hdc, VERTSIZE); ReleaseDC(0, hdc) 特别是对于多监视器配置 更新:我只需要获取普通监视器的大小,因为普通监视器的物理大小是恒定的。无法确定windo

如何获得显示器的尺寸(厘米或英寸)

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

HDC hdc = CreateDC(_T("DISPLAY"),dd.DeviceName,NULL,NULL);
int width = GetDeviceCaps(hdc, HORZSIZE);
int height = GetDeviceCaps(hdc, VERTSIZE);
ReleaseDC(0, hdc)
特别是对于多监视器配置


更新:我只需要获取普通监视器的大小,因为普通监视器的物理大小是恒定的。

无法确定windows上视频设备的确切物理大小,因为这取决于很多变量(例如活动监视器配置文件、水平/垂直分辨率、像素大小等),其中一些不受计算机控制


以投影仪设备为例,其物理尺寸取决于到投影区域的距离,而投影区域的距离无法通过编程确定,因为视频投影仪可以随时手动移动。

您可以从请求LOGPIXELSX以获取显示的DPI,尽管它通常返回96。另请参见此图。

您无法获得真实的精确大小-您可以根据windows中的DPI设置和屏幕分辨率获得近似值,但您不能保证这是真实大小

特别是在具有不同显示器(例如19英寸CRT和24英寸LCD)的多显示器情况下。此外,如果显示器是CRT,则测量是管测量,而不是显示区域

当程序在过去需要这些信息时,他们会在屏幕上显示一个量规,让用户将一张纸举到屏幕上,用量规测量纸张宽度。如果纸张为8.5英寸或A4,则您知道宽度,您可以使用他们输入的数字计算给定显示器的实际DPI。您可能需要让他们对多显示器设置中的每个显示器执行此操作


-Adam

我找到了另一种方法。监视器的物理大小存储在EDID中,窗口几乎总是其值在注册表中的副本。如果可以解析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;
}
BOOL GetMonitorDevice(TCHAR*适配器名称、显示设备和ddMon)
{
德沃德·德夫蒙=0;
while(枚举显示设备(适配器名称、devMon和ddMon、0))
{
如果(ddMon.StateFlags&显示设备处于活动状态&&
ddMon.StateFlags&DISPLAY_DEVICE_ATTACHED)//对于ATI,Windows XP
打破
devMon++;
}
if(ddMon.DeviceString[0]='\0')
{
EnumDisplayDevices(adapterName,0和ddMon,0);
if(ddMon.DeviceString[0]='\0')
_tcscpy_s(ddMon.DeviceString,_T(“默认监视器”);
}
返回ddMon.DeviceID[0]!='\0';
}
BOOL GetMonitorSizeFromEDID(TCHAR*适配器名称、DWORD和宽度、DWORD和高度)
{
显示设备ddMon;
零内存(&ddMon,sizeof(ddMon));
ddMon.cb=sizeof(ddMon);
//阅读edid
布尔结果=假;
宽度=0;
高度=0;
if(GetMonitorDevice(适配器名称、ddMon))
{
TCHAR模型[8];
TCHAR*s=\u tcschr(ddMon.DeviceID,'\\'')+1;
尺寸长度=\u tcschr(s,“\\”)-s;
如果(len>=\u countof(型号))
len=_countof(model)-1;
_tcsncpy_s(型号,s,len);
TCHAR*path=\u tcschr(ddMon.DeviceID,'\\'')+1;
TCHAR str[MAX_PATH]=“系统\\CurrentControlSet\\Enum\\DISPLAY\\”;
_tcscat_s(str,path,_tcschr(path,'\\')-path);
路径=\u tcschr(路径“\\”)+1;
HKEY HKEY;
if(RegOpenKeyEx(HKEY\U LOCAL\U MACHINE,str,0,KEY\U READ,&HKEY)=错误\U成功)
{
dwordi=0;
DWORD大小=最大路径;
文件时间ft;
while(RegEnumKeyEx(hKey、i、str和size、NULL、NULL、NULL和ft)=错误\u成功)
{
HKEY HKEY 2;
if(RegOpenKeyEx(hKey、str、0、KEY_READ和hKey2)=错误_成功)
{
大小=最大路径;
if(RegQueryValueEx(hKey2,_T(“驱动程序”),NULL,NULL,(LPBYTE)&str,&size)==ERROR\u SUCCESS)
{
如果(_tcscmp(str,path)==0)
{
HKEY hKey3;
if(RegOpenKeyEx(hKey2,_T(“设备参数”)、0、键读取和hKey3)=错误成功)
{
字节EDID[256];
尺寸=256;
if(RegQueryValueEx(hKey3,_T(“EDID”)、NULL、NULL、(LPBYTE)和EDID,&size)=ERROR\u SUCCESS)
{
德沃德p=8;
TCHAR模型2[9];
char字节1=EDID[p];
字符字节2=EDID[p+1];
模型2[0]=((字节1&0x7C)>>2)+64;
模型2[1]=((字节1和字节3)>5)+64;
model2[2]=(字节2&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);
如果(_tcscmp(模型,模型2)==0)
{
宽度=EDID[22];
高度=EDID[21];
结果=真;
}
其他的
{
//EDID不正确
}
}
RegCloseKey(hKey3);
}
}
}
RegCloseKey(hKey2);
}
i++;
}
雷克洛斯基(香港中学),;
}
}
返回结果;
}
Windows Vis