How do I get the actual Monitor name? as seen in the resolution dialog
Asked Answered
H

5

18

I am trying to grab the friendly name for the monitors on my system. I am using C#.

I have tried Screen, which just gives me //./DisplayXX. I have also tried both Win32_DesktopMonitor and EnumDisplayDevices, they all give me variations of //./DisplayXX OR Generic Monitor, whereas I know my displays names are SyncMaster and SM2333T.

Now Windows knows what these monitors are, displays them in the Devices and Printers windows with the correct names, and also in the dialog for setting location and resolution.

Where can I grab these names from? I have looked in the registry and cant seem to find them, so any help will be great.

SOLUTION: The issue I had was when calling EnumDisplayDevices the second time I was setting iDevNum to id again, which meant I was trying to grab data from the wrong place, I then replaced this with 0, and it works perfectly, see below for the code.

    var device = new DISPLAY_DEVICE();
    device.cb = Marshal.SizeOf(device);
    try
    {
        for (uint id = 0; EnumDisplayDevices(null, id, ref device, 0); id++)
        { 
                Console.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}, {5}", id, device.DeviceName, device.DeviceString, device.StateFlags, device.DeviceID, device.DeviceKey));
                Console.WriteLine();
                device.cb = Marshal.SizeOf(device);

                EnumDisplayDevices(device.DeviceName, 0, ref device, 0);

                Console.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}, {5}", id, device.DeviceName, device.DeviceString, device.StateFlags, device.DeviceID, device.DeviceKey));
                device.cb = Marshal.SizeOf(device);

                device.cb = Marshal.SizeOf(device);
                return;
            }

        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(String.Format("{0}", ex.ToString()));
    }
Hardwood answered 10/2, 2011 at 15:1 Comment(4)
It seems like you can't https://mcmap.net/q/669122/-setupdigetdeviceregistryproperty-fails-with-error_invalid_dataBowne
@OhadSchneider take a look at my question, I have provided a solution and this has been working fine in that project for a long time now.Hardwood
The answer is right here: #26405482Dinahdinan
github.com/r1me/delphi-monitorhelperRipple
C
16

After you get a DisplayDevice.DeviceName like //./DisplayX from EnumDisplayDevices, you are supposed to call 'EnumDisplayDevices' a second time, this time providing the 'DisplayDevice.DeviceName' that you got from the previous call as lpDevice, and '0' as iDevNum. Then you'll have the monitor name in DisplayDevice.DeviceString.

Carberry answered 10/2, 2011 at 19:58 Comment(12)
Ah! I will check that out, I did do the second called but was looking under DeviceName again ;) Thanks, If this would I will mark as correctHardwood
Nope that didnt work it either gave me an empty string or Generic PNP Monitor not its actual name :(Hardwood
@James - There's something strange with that result, you shouldn't get either this or that. You should always get the same string with every call. BTW, I never saw a monitor entry in the 'devices and printers' view, that's new for me. Are those names the same with what you see in 'Device Manager' under 'Monitors'?Carberry
When I said either empty or generic I meant for each monitor, as I have 5 on this machine. In Device Manager they all show as Generic Pnp Monitors except for the SyncMaster.Hardwood
Oh an as for the monitors in Devices and Printers I think its a windows7 thing as Ive never seen it before either :)Hardwood
@James - I see, thanks. Perhaps you just have too much monitors for EnumDisplayDevices to handle. ;) You might like to give it a shot with WMI, here's an example.Carberry
@Sertac I tried WMI and it only gives me 3 displays :S I finally got it to return the right values, we were both almost there. I will post my solution, now.Hardwood
This post helped me to find the solution, which I have posted in the original question.Hardwood
@James - I had mentioned 'iDevNum' would be passed '0' for the second call in the answer. ;) Glad you sorted it out in any case. :)Carberry
oops! so you did :S sorry about that.Hardwood
Interesting; this doesn't work for me. It only gives me "Generic PnP Monitor", whereas the Control Panel shows "SyncMaster".Triadelphous
I get the same results as @luke. It returns "Generic PnP Monitor" for all monitors.Happygolucky
D
26

Examine carefully! this is what you looking for, you can now write Screen.PrimaryScreen.DeviceFriendlyName() and get the real name of the monitor device.
(and yes, it is the same name seen in resolution dialog)

While I did add some personal touch to wrap this code I did not create the Hard-Core part of it, And so I would like to thank 2 developers, The MS developer who gave the essentials in C++ and the anonymous developer who translated those essentials to C# code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Tools;

namespace ConsoleApplication35
{
    internal class Program
    {

        private static void Main()
        {

            Console.WriteLine(Screen.PrimaryScreen.DeviceFriendlyName());

            //output: ASUS MK241

            Console.ReadLine();
        }
    }
}

namespace Tools
{
    public static class ScreenInterrogatory
    {
        public const int ERROR_SUCCESS = 0;

        #region enums

        public enum QUERY_DEVICE_CONFIG_FLAGS : uint
        {
            QDC_ALL_PATHS = 0x00000001,
            QDC_ONLY_ACTIVE_PATHS = 0x00000002,
            QDC_DATABASE_CURRENT = 0x00000004
        }

        public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
        {
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
        {
            DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
            DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
            DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_ROTATION : uint
        {
            DISPLAYCONFIG_ROTATION_IDENTITY = 1,
            DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
            DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
            DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
            DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_SCALING : uint
        {
            DISPLAYCONFIG_SCALING_IDENTITY = 1,
            DISPLAYCONFIG_SCALING_CENTERED = 2,
            DISPLAYCONFIG_SCALING_STRETCHED = 3,
            DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
            DISPLAYCONFIG_SCALING_CUSTOM = 5,
            DISPLAYCONFIG_SCALING_PREFERRED = 128,
            DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_PIXELFORMAT : uint
        {
            DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
            DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
            DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
            DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
            DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
            DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff
        }

        public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
        {
            DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
            DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
            DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
        {
            DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
            DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
            DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
            DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
        }

        #endregion

        #region structs

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public uint LowPart;
            public int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_SOURCE_INFO
        {
            public LUID adapterId;
            public uint id;
            public uint modeInfoIdx;
            public uint statusFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_TARGET_INFO
        {
            public LUID adapterId;
            public uint id;
            public uint modeInfoIdx;
            private DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
            private DISPLAYCONFIG_ROTATION rotation;
            private DISPLAYCONFIG_SCALING scaling;
            private DISPLAYCONFIG_RATIONAL refreshRate;
            private DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
            public bool targetAvailable;
            public uint statusFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_RATIONAL
        {
            public uint Numerator;
            public uint Denominator;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_INFO
        {
            public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
            public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
            public uint flags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_2DREGION
        {
            public uint cx;
            public uint cy;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
        {
            public ulong pixelRate;
            public DISPLAYCONFIG_RATIONAL hSyncFreq;
            public DISPLAYCONFIG_RATIONAL vSyncFreq;
            public DISPLAYCONFIG_2DREGION activeSize;
            public DISPLAYCONFIG_2DREGION totalSize;
            public uint videoStandard;
            public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_TARGET_MODE
        {
            public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINTL
        {
            private int x;
            private int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_SOURCE_MODE
        {
            public uint width;
            public uint height;
            public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
            public POINTL position;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct DISPLAYCONFIG_MODE_INFO_UNION
        {
            [FieldOffset(0)]
            public DISPLAYCONFIG_TARGET_MODE targetMode;

            [FieldOffset(0)]
            public DISPLAYCONFIG_SOURCE_MODE sourceMode;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_MODE_INFO
        {
            public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
            public uint id;
            public LUID adapterId;
            public DISPLAYCONFIG_MODE_INFO_UNION modeInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
        {
            public uint value;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
        {
            public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
            public uint size;
            public LUID adapterId;
            public uint id;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct DISPLAYCONFIG_TARGET_DEVICE_NAME
        {
            public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
            public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
            public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
            public ushort edidManufactureId;
            public ushort edidProductCodeId;
            public uint connectorInstance;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string monitorFriendlyDeviceName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string monitorDevicePath;
        }

        #endregion

        #region DLL-Imports

        [DllImport("user32.dll")]
        public static extern int GetDisplayConfigBufferSizes(
            QUERY_DEVICE_CONFIG_FLAGS flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);

        [DllImport("user32.dll")]
        public static extern int QueryDisplayConfig(
            QUERY_DEVICE_CONFIG_FLAGS flags,
            ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] PathInfoArray,
            ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] ModeInfoArray,
            IntPtr currentTopologyId
            );

        [DllImport("user32.dll")]
        public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName);

        #endregion

        private static string MonitorFriendlyName(LUID adapterId, uint targetId)
        {
            var deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME
            {
                header =
                {
                    size = (uint)Marshal.SizeOf(typeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)),
                    adapterId = adapterId,
                    id = targetId,
                    type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
                }
            };
            var error = DisplayConfigGetDeviceInfo(ref deviceName);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);
            return deviceName.monitorFriendlyDeviceName;
        }

        private static IEnumerable<string> GetAllMonitorsFriendlyNames()
        {
            uint pathCount, modeCount;
            var error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);

            var displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount];
            var displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount];
            error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,
                ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);

            for (var i = 0; i < modeCount; i++)
                if (displayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET)
                    yield return MonitorFriendlyName(displayModes[i].adapterId, displayModes[i].id);
        }

        public static string DeviceFriendlyName(this Screen screen)
        {
            var allFriendlyNames = GetAllMonitorsFriendlyNames();
            for (var index = 0; index < Screen.AllScreens.Length; index++)
                if (Equals(screen, Screen.AllScreens[index]))
                    return allFriendlyNames.ToArray()[index];
            return null;
        }

    }

}
Dinahdinan answered 31/1, 2015 at 23:42 Comment(5)
Great answer that successfully works. The only missing answer is the ability to query for Front Porch, Sync, and Back Porch. I would like to figure out a way to query for full video signal timings information.Flatboat
Can your solution be extended and get a diagonal size? Or physical width and height?Pose
@Pose you mean "physical" - as how many inches? nah - I don't think it exists anywhere electronically, I think only pixels count is available. but you could have a long dictionary of all models and etc.. but then.. who will maintain it? I suggest you just let your user define it per screen if you need that information available for some processing.Dinahdinan
@G.Y, I don't really need to know the physical size of the screen (in inches), but I need to find out the PPI (pixel per inch). I only need the physical size to calculate the PPI. Is there any way to find out the PPI of all connected monitors? Now I use "WmiMonitorBasicDisplayParams" class but the properties "MaxHorizontalImageSize" and "MaxVerticalImageSize" are only uint8 and do not match exactly with the device physical width and height.Pose
For those that want a C/C++ version of this, learn.microsoft.com/en-us/windows/win32/api/winuser/… is an example in the MS docsDiopside
C
16

After you get a DisplayDevice.DeviceName like //./DisplayX from EnumDisplayDevices, you are supposed to call 'EnumDisplayDevices' a second time, this time providing the 'DisplayDevice.DeviceName' that you got from the previous call as lpDevice, and '0' as iDevNum. Then you'll have the monitor name in DisplayDevice.DeviceString.

Carberry answered 10/2, 2011 at 19:58 Comment(12)
Ah! I will check that out, I did do the second called but was looking under DeviceName again ;) Thanks, If this would I will mark as correctHardwood
Nope that didnt work it either gave me an empty string or Generic PNP Monitor not its actual name :(Hardwood
@James - There's something strange with that result, you shouldn't get either this or that. You should always get the same string with every call. BTW, I never saw a monitor entry in the 'devices and printers' view, that's new for me. Are those names the same with what you see in 'Device Manager' under 'Monitors'?Carberry
When I said either empty or generic I meant for each monitor, as I have 5 on this machine. In Device Manager they all show as Generic Pnp Monitors except for the SyncMaster.Hardwood
Oh an as for the monitors in Devices and Printers I think its a windows7 thing as Ive never seen it before either :)Hardwood
@James - I see, thanks. Perhaps you just have too much monitors for EnumDisplayDevices to handle. ;) You might like to give it a shot with WMI, here's an example.Carberry
@Sertac I tried WMI and it only gives me 3 displays :S I finally got it to return the right values, we were both almost there. I will post my solution, now.Hardwood
This post helped me to find the solution, which I have posted in the original question.Hardwood
@James - I had mentioned 'iDevNum' would be passed '0' for the second call in the answer. ;) Glad you sorted it out in any case. :)Carberry
oops! so you did :S sorry about that.Hardwood
Interesting; this doesn't work for me. It only gives me "Generic PnP Monitor", whereas the Control Panel shows "SyncMaster".Triadelphous
I get the same results as @luke. It returns "Generic PnP Monitor" for all monitors.Happygolucky
T
5

This information is almost certainly obtained through the SetupAPI family of functions. I don't recall the specifics off the top of my head, but you will need to get all monitor devices (GUID_DEVINTERFACE_MONITOR) and obtain their friendly names (SPDRP_FRIENDLYNAME).

Triadelphous answered 10/2, 2011 at 15:54 Comment(1)
I tried to do as you suggest to no avail, would be great if you could take a look: #24356789Bowne
D
4

From here: Get Exact Monitor/Display/Screen Name

Well, this question is old, however, as for the sake of google redirects, I suggest my 'WindowsDisplayAPI' library.

https://www.nuget.org/packages/WindowsDisplayAPI


Using the library, there are multiple ways to get the display name. The simplest way is:

foreach (var display in Display.GetDisplays())
{
    Console.WriteLine(display.DeviceName);
}

But this is using the old API, if you are sure that your program targets at least Windows Vista, I suggest the following code:

foreach (var target in DisplayConfig.PathDisplayTarget.GetDisplayTargets())
{
    Console.WriteLine(target.FriendlyName);
}
Determiner answered 18/5, 2017 at 11:44 Comment(4)
You should probably mention you are the author.Pythoness
@RonnieW, done. Not that it mattered tho, both the GitHub project page and the NuGet package page clearly state that.Determiner
Beware, the NuGet is under LGPL v3.Annettannetta
@YurySchkatula, you are confusing LGPL with GPL. https://mcmap.net/q/181652/-gpl-and-lgpl-open-source-licensing-restrictions-closedDeterminer
B
0

I have been seraching for an answer to this same question. In this link it is mentioned that generic pnp monitor is shown, because there is no driver installed for the monitor and the device is running with the Generic PnP Monitor Driver.

For windows 7 and higher there seems to be a different function than EnumDisplayDevices to get the desired display names as shown in the control panel. This can be done with the DisplayConfigGetDeviceInfo function as explained here. I hope someone soon can translate this to Delphi, which I am looking for.

Bezel answered 10/8, 2014 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.