Link info from EnumDisplayDevices with info from SetupDiOpenDevRegKey (EDID)

1.3k views Asked by At

Windows 7, multi-monitors configurations.

Cross compiled on linux (opensuse 13.1) with gcc-mingw-5.1.0 (which may actually be the cause of me not getting the expected values).

I get a list of all display devices with EnumDisplayDevices: Code:

int DispNum = 0;
DISPLAY_DEVICE DisplayDevice;
DEVMODE defaultMode;

// initialize DisplayDevice
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);

while (EnumDisplayDevices(NULL, DispNum, &DisplayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
    ZeroMemory(&defaultMode, sizeof(DEVMODE));
    defaultMode.dmSize = sizeof(DEVMODE);

    if ((DisplayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE) && (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) && !(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) {
        printf("%d -> %s\n\tstr=%s\n\tid=%s\n\tkey=%s\n\tprimary=%s\n", DispNum,DisplayDevice.DeviceName, DisplayDevice.DeviceString,
            DisplayDevice.DeviceID, DisplayDevice.DeviceKey,
            (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? "y":"n");

        if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &defaultMode) ) {
            puts("EnumDisplaySettings failed\n");
        } else {
            printf("    -> bpp=%d w=%d h=%d fps=%d\n",
                (int)defaultMode.dmBitsPerPel, (int)defaultMode.dmPelsWidth,
                (int)defaultMode.dmPelsHeight, (int)defaultMode.dmDisplayFrequency);
        }
    }

    // Reinit DisplayDevice just to be extra clean
    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
    DisplayDevice.cb = sizeof(DisplayDevice);
    DispNum++;
}

Output (emphasis mine):

0 -> \.\DISPLAY1
str=Intel(R) HD Graphics 4600
id=PCI\VEN_8086&DEV_0416&SUBSYS_397817AA&REV_06
key=\Registry\Machine\System\CurrentControlSet\Control\Video{BBECD187-6CE4-47FD-915A-A4952B2AC000}\0000
primary=y
-> bpp=32 w=1920 h=1080 fps=60

1 -> \.\DISPLAY2
str=Intel(R) HD Graphics 4600
id=PCI\VEN_8086&DEV_0416&SUBSYS_397817AA&REV_06
key=\Registry\Machine\System\CurrentControlSet\Control\Video{BBECD187-6CE4-47FD-915A-A4952B2AC000}\0001
primary=n
-> bpp=32 w=1920 h=1080 fps=60

Now, with this article I can get the EDID of each monitor:

const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18};

HDEVINFO devInfo = NULL;
SP_DEVINFO_DATA devInfoData;
ULONG i = 0;

devInfo = SetupDiGetClassDevsEx(
    &GUID_CLASS_MONITOR, //class GUID
    NULL,NULL,
    DIGCF_PRESENT,
    NULL,NULL,NULL);

if (NULL == devInfo)
return -1;

for (i=0;ERROR_NO_MORE_ITEMS != GetLastError();i++) {
    memset(&devInfoData,0,sizeof(devInfoData));
    devInfoData.cbSize = sizeof(devInfoData);

    if (SetupDiEnumDeviceInfo(devInfo,i,&devInfoData))
    {
        // look for EDID with SetupDiOpenDevRegKey + RegEnumValue...
    }
}

Output (part of it):

...
Found value EDID for 'PnP-Monitor (Standard)'
Key path is '\REGISTRY\MACHINE\SYSTEM\ControlSet001\Enum\DISPLAY\LGD044F\4&1BDB7018&0&UID68092928\Device Parameters'

00 ff ff ff ff ff ff 00 26 07 01 00 e7 03 00 00
00 1a 01 03 80 00 00 00 02 00 00 00 00 00 00 00
....

My problem is now, how do I link both informations? How do I attribute an EDID to a Display?

Expected:

\.\DISPLAY1 -> EDID1

\.\DISPLAY2 -> EDID2

Notes

  1. Display #1 is an LG monitor, Display #2 is a Dell (setup as such and this can be verified when I change the resolution of Display#2), but the EDID for the Dell monitor appears first and then comes the EDID of the LG. Therefore I cannot use the order of appearance in both enumerations, they are not directly linked (otherwise no question to ask).

  2. I also cannot rely on the resolution information or sync rate, since it may be the same for all monitors

  3. I am aware of this question and its answer but the accepted answer does not help me since it expects DISPLAY_DEVICE.DeviceID to be in the reg key \HKLM\System\CurrentControlSet\Enum\DISPLAY and what I get from EnumDisplayDevices is in \HKLM\System\CurrentControlSet\Enum\PCI (see the "id" lines in the output).

  4. I tried to use the flag EDD_GET_DEVICE_INTERFACE_NAME as advised in this question but I do not get the deviceID as shown in the accepted answer.

  5. how to get the key path

I have checked the list of SetupAPI functions but could not find how to connect display information and the result of SetupDiOpenDevRegKey.

What did I miss? Which flag did I set wrong? Can somehow I use the Key path returned by SetupDiOpenDevRegKey?

Thanks a lot.

1

There are 1 answers

0
ramzes2 On

You need to call EnumDisplayDevices function twice for each display, like this: Getting the monitor's name with EnumDisplayDevices

First call with lpDevice=NULL and second call with lpDevice=DisplayDevice.DeviceName

After that you received expected value in DISPLAY_DEVICE.DeviceID. For my case it has next value "MONITOR\DVAF001\{4d36e96e-e325-11ce-bfc1-08002be10"