tags:

views:

1607

answers:

6

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.

+5  A: 

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
+1, You'd have to wonder what use it would be to know the physical size rather than the actual resolution.
sixlettervariables
horicontal => horizontal
SAMills
/me thinks Kosi2801 just outed himself as being German, by using the word "beamer". It really doesn't mean "video projector" in English. :)
unwind
hehe, now I know the slang German for projector. Nice! Stackoverflow as a technical cross cultural melting pot - awesome.
Adam Davis
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
Corrected my english mistakes. Thanks for the hints.
Kosi2801
A: 

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
+3  A: 

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 Davis
+8  A: 

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)
    {
        EnumDisplayDevices(adapterName, 0, &ddMon, 0);
        if (!*ddMon.DeviceString)
            _tcscpy_s(ddMon.DeviceString, _T("Default Monitor"));
    }
    return ddMon.DeviceID != '\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
I've always been curious about the communications channel between a monitor and the graphics interface - thanks for giving the name!
Mark Ransom
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
@devo yea, it's just way too deeply nested. I'd recommend refactoring this code if you plan on using it
Earlz
Also, it is good to note that not all monitors provide EDID information.
Earlz
haha, takes C 100 lines of code to get monitor size.
Haoest
+2  A: 

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

KindDragon
A: 

You can obtain EDID from the registry.

ZeroElement