11

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.

KindDragon
  • 6,558
  • 4
  • 47
  • 75

7 Answers7

20

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;
}
KindDragon
  • 6,558
  • 4
  • 47
  • 75
  • I've always been curious about the communications channel between a monitor and the graphics interface - thanks for giving the name! – Mark Ransom Oct 06 '09 at 22:06
  • 4
    A bit more indentation would be nice. That'd make sure I couldn't see the full lines on my 30' computer screen. – devoured elysium Apr 30 '10 at 21:55
  • @devo yea, it's just way too deeply nested. I'd recommend refactoring this code if you plan on using it – Earlz Apr 30 '10 at 22:11
  • 6
    Also, it is good to note that not all monitors provide EDID information. – Earlz Apr 30 '10 at 22:12
  • This registry path is probably device specific, and anyway undocumented. There is a documented alternative - I've put it as an answer below. – Ofek Shilon Nov 26 '11 at 21:22
  • 1
    You need to do something reasonable if the EDID isn't there. (It's not on my machine.) You also have to take into account things like projectors, where the size of the image depends on the throw distance, zoom setting, etc. – Adrian McCarthy Jan 16 '15 at 20:39
  • The code `ddMon.DeviceID != '\0';` compares a `TCHAR` pointer to `'\0'`. Perhaps you forgot a reference star? – Gutblender Nov 04 '15 at 21:31
  • 3
    @KingDragon: I believe some credit is in place. https://ofekshilon.com/2014/06/19/reading-specific-monitor-dimensions/ – Ofek Shilon Nov 08 '16 at 16:52
  • Code sample appears to have swapped width and height. – Adrian McCarthy Oct 30 '17 at 21:06
  • 1
    I have not tested to run this code, but I don't think it would work on my computer. It would just return bytes 22 and 21, which doesn't give my screen dimensions. What does work is the link provided by ofekshilon.com (see comment above) which uses bytes 66, 67 and 68, and gives dimensions in millimeters. On my screen I correctly get w=480mm and h=270mm. – youen Dec 12 '18 at 09:42
  • I think byte 21 and 22, give display size in cm... that is approximate, but perhaps good enough. However, for some reason Adobe, Gimp, Visio, Word seem to be atuned to some other value with zoom being 100%. The point would be to fix the metrics these programs use. On my setup I get screen content about 7% too large. – user377178 Sep 17 '19 at 19:29
9

Navigating the registry directly is not only unsupported, but actually fails for devices different than yours. (e.g., the one on which I tested your code).

Unlike what some here say, there is an official way of accessing the EDID key path: by use of the Setup API, and specifically SetupDiOpenDevRegKey.

There's some tedious setup involved - Sample code is here.


EDIT: multiple monitors are handled here.

Ofek Shilon
  • 14,734
  • 5
  • 67
  • 101
  • Your code does not work for multiple monitors since GetsizeForDevID does ignore the used device it always retrieves the size of the last one. Size of first is always ignored. – Samuel Sep 20 '13 at 11:14
  • 1
    Warning: EDID is not available for all monitors. – Adrian McCarthy Apr 01 '18 at 21:52
7

It is not possible to determine the exact physical size of a video device on windows as this depends on quite a lot of variables (e.g. active monitor profile, horizontal/vertical resolution, pixel size, etc.), some of which are not under the control of the computer.

Think for example of projector devices, where the physical size depends on the distance to the projection area which cannot be determined programmatically, as the video projector could be moved manually anytime.

Kosi2801
  • 22,222
  • 13
  • 38
  • 45
  • 8
    +1, You'd have to wonder what use it would be to know the physical size rather than the actual resolution. – user7116 Feb 23 '09 at 14:27
  • /me thinks Kosi2801 just outed himself as being German, by using the word "beamer". It really doesn't mean "video projector" in English. :) – unwind Feb 23 '09 at 14:37
  • hehe, now I know the slang German for projector. Nice! Stackoverflow as a technical cross cultural melting pot - awesome. – Adam Davis Feb 23 '09 at 14:59
  • 1
    Sixlettervariables, you'd want to know the physical size whenever you want to display something, such as a page of text, at "actual size." Maybe in a print-preview scenario. – Rob Kennedy Feb 23 '09 at 15:09
  • Corrected my english mistakes. Thanks for the hints. – Kosi2801 Feb 23 '09 at 16:36
  • 5
    How exactly could horizontal/vertical resolution and pixel size affect the **physical** size of a monitor? I've changed resolution a lot, and I've never noticed my monitor growing or shrinking. True about projectors, but that doesn't automatically imply that getting the physical size is *always* impossible. Just that it's impossible for projectors and the like. – jalf Sep 06 '11 at 08:35
  • 1
    On a CRT monitor, changing resolutions and pixel size can affect how much of the tube is used to display the image, effectively changing the size of the display. CRT images tend to shrink slightly with the age of the tube, which is why many display schemes overscan. – Adrian McCarthy Apr 01 '18 at 21:55
5

You can't get the real exact size - you can get an approximation that depends on the DPI setting in windows, and the resolution of the screen, but you can't guarantee that this is the real size.

Especially in a multimonitor situation with different displays (say a 19" CRT and 24" LCD). Further, if the display is CRT then the measurement is the tube measurement, and not the display area.

When programs have needed this information exactly in the past, they've shown a gauge onscreen, and had the user hold a piece of paper up to the screen and measure the paper width with the gauge. Given the paper is 8.5" or A4 then you know the width, and you can use the number that they input to figure out the real DPI for a given display. You may need to have them do that for each monitor in a multimonitor setup.

-Adam

Adam Davis
  • 91,931
  • 60
  • 264
  • 330
4

Windows Vista and upper support new function GetMonitorDisplayAreaSize() http://msdn.microsoft.com/en-us/library/ms775210%28VS.85%29.aspx

Update: It doesn't work properly

KindDragon
  • 6,558
  • 4
  • 47
  • 75
1

You can request LOGPIXELSX from GetDeviceCaps to get the DPI for the display, though it will generally return 96. See also this MSDN article on writing DPI-aware apps.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
0

You can obtain EDID from the registry.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292