cwindowswinapimonitor

How to obtain the correct physical size of the monitor?


How can I get the size of the display in centimeters or inches?

This code does not always works correctly:

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

Especially for multi-monitor configuration.

Update: I need to get the size just for ordinary monitors, which have a constant physical size.


Solution

  • I found another way. The physical size of the monitor are stored in the EDID, and Windows are almost always copies of its value in the registry. If you can parse EDID, you can read the width and height of the monitor in centimeters.

    Update: Added code

    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;
    }