Как получить правильный физический размер монитора? - PullRequest
10 голосов
/ 23 февраля 2009

Как узнать размер дисплея в сантиметрах или дюймах?

Этот код не всегда работает правильно:

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

Специально для конфигурации с несколькими мониторами.

Обновление: Мне нужно получить размер только для обычных мониторов, которые имеют постоянный физический размер.

Ответы [ 7 ]

18 голосов
/ 24 февраля 2009

Я нашел другой способ. Физический размер монитора хранится в 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;
}
8 голосов
/ 23 февраля 2009

Невозможно определить точный физический размер видеоустройства на окнах, поскольку это зависит от множества переменных (например, активного профиля монитора, горизонтального / вертикального разрешения, размера пикселя и т. Д.), Некоторые из которых не под контролем компьютера.

Представьте, например, устройства проектора, физический размер которых зависит от расстояния до области проекции, которое не может быть определено программно, поскольку видеопроектор можно перемещать вручную в любое время.

6 голосов
/ 27 ноября 2011

Навигация по реестру напрямую не только не поддерживается, но на самом деле дает сбой для устройств, отличных от вашего. (например, тот, на котором я тестировал ваш код).

В отличие от того, что некоторые здесь говорят, является официальным способом доступа к ключу EDID: с помощью API настройки, в частности SetupDiOpenDevRegKey .

В этом участвует некоторая утомительная настройка - Пример кода здесь .


РЕДАКТИРОВАТЬ: несколько мониторов обрабатываются здесь .

5 голосов
/ 23 февраля 2009

Вы не можете получить реальный точный размер - вы можете получить приблизительное значение, которое зависит от настроек DPI в окнах и разрешения экрана, но вы не можете гарантировать, что это реальный размер.

Особенно в ситуации с несколькими мониторами с разными дисплеями (скажем, 19 "ЭЛТ и 24" ЖКД). Кроме того, если на дисплее отображается ЭЛТ, то измерением является измерение трубки, а не области отображения.

Когда программы нуждались в этой информации точно в прошлом, они показывали на экране манометр и заставляли пользователя подносить лист бумаги к экрану и измерять ширину бумаги с помощью манометра. Учитывая, что бумага имеет размер 8,5 "или A4, тогда вы знаете ширину и можете использовать число, которое они вводят, чтобы выяснить реальное значение DPI для данного дисплея. Возможно, вам потребуется, чтобы они делали это для каждого монитора в настройке с несколькими мониторами.

-Adam

4 голосов
/ 01 мая 2010

Windows Vista и верхняя поддержка новой функции GetMonitorDisplayAreaSize () http://msdn.microsoft.com/en-us/library/ms775210%28VS.85%29.aspx

Обновление: не работает должным образом

2 голосов
/ 23 февраля 2009

Вы можете запросить LOGPIXELSX у GetDeviceCaps , чтобы получить DPI для дисплея, хотя обычно он возвращает 96. См. Также эту статью MSDN о написании приложений с поддержкой DPI .

0 голосов
/ 04 октября 2010

Вы можете получить EDID из реестра.

...