Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EnumDisplayDevices not returning anything

Tags:

c#

winapi

I am having an issue working with EnumDisplayDevices in C#. I used the code posted here and it worked seamlessly. However recently I switched to coding the application on my desktop computer. The code no longer works, not giving me anything.

If it helps, my monitor is an LG W2753VC running on an AMD Radeon HD 5770.

Here is my current code:

        var device = new DISPLAY_DEVICE();

        device.cb = Marshal.SizeOf(device);
        try {
            for (uint id = 0; EnumDisplayDevices(null, id, ref device, 0); id++) {
                device.cb = Marshal.SizeOf(device);
                EnumDisplayDevices(device.DeviceName, 0, ref device, 0);
                device.cb = Marshal.SizeOf(device);

                Console.WriteLine("id={0}, name={1}, devicestring={2}", id, device.DeviceName, device.DeviceString);
                if (device.DeviceName == null || device.DeviceName == "") continue;
            }
        } catch (Exception ex) { }

What I'm getting on my laptop:

id=0, name=\\.\DISPLAY1\Monitor0, devicestring=Generic PnP Monitor

(That should be "Mobile PC Display", but it's not the problem here)

What I'm getting on my desktop:

id=0, name=, devicestring=
id=1, name=, devicestring=

Am I doing this wrong, and if not, is there any other way to get all connected displays? I have already tried the WMI and registry approach.

like image 441
pbondoer Avatar asked Aug 23 '26 09:08

pbondoer


2 Answers

Hard to tell without you posting all your p/invoke code. Here's code that works on my workstation:

public class EnumDisplayDevicesTest
{
    [DllImport("user32.dll")]
    static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

    [Flags()]
    public enum DisplayDeviceStateFlags : int
    {
        /// <summary>The device is part of the desktop.</summary>
        AttachedToDesktop = 0x1,
        MultiDriver = 0x2,
        /// <summary>The device is part of the desktop.</summary>
        PrimaryDevice = 0x4,
        /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
        MirroringDriver = 0x8,
        /// <summary>The device is VGA compatible.</summary>
        VGACompatible = 0x10,
        /// <summary>The device is removable; it cannot be the primary display.</summary>
        Removable = 0x20,
        /// <summary>The device has more display modes than its output devices support.</summary>
        ModesPruned = 0x8000000,
        Remote = 0x4000000,
        Disconnect = 0x2000000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct DISPLAY_DEVICE
    {
        [MarshalAs(UnmanagedType.U4)]
        public int cb;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string DeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceString;
        [MarshalAs(UnmanagedType.U4)]
        public DisplayDeviceStateFlags StateFlags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceID;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceKey;
    }

    public void Display()
    {
        DISPLAY_DEVICE d = new DISPLAY_DEVICE();
        d.cb = Marshal.SizeOf(d);
        try
        {
            for (uint id = 0; EnumDisplayDevices(null, id, ref d, 0); id++)
            {
                if (d.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop))
                {
                    Console.WriteLine(
                        String.Format("{0}, {1}, {2}, {3}, {4}, {5}",
                                 id,
                                 d.DeviceName,
                                 d.DeviceString,
                                 d.StateFlags,
                                 d.DeviceID,
                                 d.DeviceKey
                                 )
                                 );
                    d.cb = Marshal.SizeOf(d);
                    EnumDisplayDevices(d.DeviceName, 0, ref d, 0);
                    Console.WriteLine(
                        String.Format("{0}, {1}",
                                 d.DeviceName,
                                 d.DeviceString
                                 )
                                 );
                }
                d.cb = Marshal.SizeOf(d);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(String.Format("{0}", ex.ToString()));
        }
    }
}

The above code works as the OP desires on my machines, not sure why it won't work on his laptop.

An alternative method to getting the info is listed below, taken from here:

foreach (var display in DisplayDetails.GetMonitorDetails())
{
    Console.WriteLine(display.Model);
}

public class DisplayDetails
{
    public string PnPID { get; set; }

    public string SerialNumber { get; set; }

    public string Model { get; set; }

    public string MonitorID { get; set; }

    /// <summary>
    /// The Constructor to create a new instances of the DisplayDetails class...
    /// </summary>
    public DisplayDetails(string sPnPID, string sSerialNumber, string sModel, string sMonitorID)
    {
        PnPID = sPnPID;
        SerialNumber = sSerialNumber;
        Model = sModel;
        MonitorID = sMonitorID;
    }

    /// <summary>
    /// This Function returns all Monitor Details
    /// </summary>
    /// <returns></returns>
    static public IEnumerable<DisplayDetails> GetMonitorDetails()
    {
        //Open the Display Reg-Key
        RegistryKey Display = Registry.LocalMachine;
        Boolean bFailed = false;
        try
        {
            Display = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\DISPLAY");
        }
        catch
        {
            bFailed = true;
        }

        if (!bFailed & (Display != null))
        {

            //Get all MonitorIDss
            foreach (string sMonitorID in Display.GetSubKeyNames())
            {
                RegistryKey MonitorID = Display.OpenSubKey(sMonitorID);

                if (MonitorID != null)
                {
                    //Get all Plug&Play ID's
                    foreach (string sPNPID in MonitorID.GetSubKeyNames())
                    {
                        RegistryKey PnPID = MonitorID.OpenSubKey(sPNPID);
                        if (PnPID != null)
                        {
                            string[] sSubkeys = PnPID.GetSubKeyNames();

                            //Check if Monitor is active
                            if (sSubkeys.Contains("Control"))
                            {
                                if (sSubkeys.Contains("Device Parameters"))
                                {
                                    RegistryKey DevParam = PnPID.OpenSubKey("Device Parameters");
                                    string sSerial = "";
                                    string sModel = "";

                                    //Define Search Keys
                                    string sSerFind = new string(new char[] { (char)00, (char)00, (char)00, (char)0xff });
                                    string sModFind = new string(new char[] { (char)00, (char)00, (char)00, (char)0xfc });

                                    //Get the EDID code
                                    byte[] bObj = DevParam.GetValue("EDID", null) as byte[];
                                    if (bObj != null)
                                    {
                                        //Get the 4 Vesa descriptor blocks
                                        string[] sDescriptor = new string[4];
                                        sDescriptor[0] = Encoding.Default.GetString(bObj, 0x36, 18);
                                        sDescriptor[1] = Encoding.Default.GetString(bObj, 0x48, 18);
                                        sDescriptor[2] = Encoding.Default.GetString(bObj, 0x5A, 18);
                                        sDescriptor[3] = Encoding.Default.GetString(bObj, 0x6C, 18);

                                        //Search the Keys
                                        foreach (string sDesc in sDescriptor)
                                        {
                                            if (sDesc.Contains(sSerFind))
                                            {
                                                sSerial = sDesc.Substring(4).Replace("\0", "").Trim();
                                            }
                                            if (sDesc.Contains(sModFind))
                                            {
                                                sModel = sDesc.Substring(4).Replace("\0", "").Trim();
                                            }
                                        }


                                    }
                                    if (!string.IsNullOrEmpty(sPNPID + sSerFind + sModel + sMonitorID))
                                    {
                                        yield return new DisplayDetails(sPNPID, sSerial, sModel, sMonitorID);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
like image 112
GalacticJello Avatar answered Aug 25 '26 23:08

GalacticJello


I had exactly this behavior when device.cb wasn't equal to one of 840 or 224 (sizeof DISPLAY_DEVICEW and DISPLAY_DEVICEA respectively). In my case I just mistakenly wrote device.cb = sizeof(device.cb); Check value of Marshal.SizeOf(device) on both your computers.

like image 26
Marvin Nimnull Avatar answered Aug 26 '26 00:08

Marvin Nimnull



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!