none
Howto get display Windows display numbers RRS feed

  • Question

  • When users setup displays in Windows a number is assigned to each display and the user can show these numbers by clicking identify. When an application wants to launch a new window I want to show these numbers to the user, to make it easy to select where the window must go. Thus I would like to know what the display number of each monitor is.

    I have tried different approaches, using the System.Windows.Forms.Screen.AllScreens which is normally used in C#/.Net to get info about monitor, but it does not contain the number. I also tried using WMI with a series of different "select" statements and a lot of different monitor info can be retrieved, but not the number.

    So how do you get the display numbers from Windows or is that impossible?

    The numbers I am looking for are the ones shown in this screenshot from Windows 10 (in this case 2 is the primary display):

    

    Thursday, December 12, 2019 2:11 PM

All replies

  • Here are the raw basics

    private void button1_Click(object sender, EventArgs e)
    {
        var screens = Screen.AllScreens;
        foreach (var screenItem in screens)
        {
            var result = Convert.ToInt32(Regex.Replace(screenItem.DeviceName, "[^0-9]", ""));
            Console.WriteLine(result);
            var index = Convert.ToInt32(Regex.Replace(Screen.FromControl(this).DeviceName, "[^0-9]", ""));
            if (result == index)
            {
                Console.WriteLine("  This is the current screen");
            }
        }
    }


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Thursday, December 12, 2019 3:04 PM
    Moderator
  • Did you check if Screen.Bounds rectangles reflect the arrange?

    Thursday, December 12, 2019 5:55 PM
  • Hi MEK_DK,

    Thank you for posting here.

    Although Screen does not have a clear serial number, we can still distinguish different displays by different DeviceNames.

    You can get the last character of DeviceName as a serial number and show it to the user so that they can choose a display.

    Screen[Bounds={X=0,Y=0,Width=1600,Height=900} WorkingArea={X=0,Y=0,Width=1600,Height=860} Primary=True DeviceName=\\.\DISPLAY1

    Screen[Bounds={X=0,Y=0,Width=1600,Height=900} WorkingArea={X=0,Y=0,Width=1600,Height=860} Primary=True DeviceName=\\.\DISPLAY2

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, December 13, 2019 8:27 AM
  • I am aware that I can distinguish the different screens by e.g. DeviceName or Screen.Bounds.

    However that name does make sense to the user because Windows uses other number (as I wrote they do not match the ones found in display settings).

    But yes before the user sends something to secondary displays something could be shown on them e.g. a temporary window.

    Does anybody else have a suggestion about how to get the display numbers from Windows?

    Friday, December 13, 2019 9:00 AM
  • On XP/Vista Windows used EnumDisplayDevices and now on my Windows 10 OS, it uses UWP
    Maybe you can do a test with EnumDisplayDevices but I don't know how the numbers are calculated (I have only 1 monitor) =>

    DISPLAY_DEVICE ddAdapter = new DISPLAY_DEVICE();
    ddAdapter.cb = Marshal.SizeOf(typeof(DISPLAY_DEVICE));
    for (uint nAdapter = 0; EnumDisplayDevices(null, nAdapter, ref ddAdapter, 0); nAdapter++)
    {
        Console.WriteLine("Adapter n°{0}", nAdapter + 1);
        Console.WriteLine("\tDevice name : {0}", ddAdapter.DeviceName);
        Console.WriteLine("\tDevice string : {0}", ddAdapter.DeviceString);
        Console.WriteLine("\tDevice ID : {0}", ddAdapter.DeviceID);
        Console.WriteLine("\tActive : {0}", ((ddAdapter.StateFlags & DISPLAY_DEVICE_ACTIVE) == DISPLAY_DEVICE_ACTIVE) ? "TRUE" : "FALSE");
        Console.WriteLine("\tPrimary : {0}", ((ddAdapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) == DISPLAY_DEVICE_PRIMARY_DEVICE) ? "TRUE" : "FALSE");
        Console.WriteLine("\tAttached : {0}", ((ddAdapter.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ? "TRUE" : "FALSE");
    
        IntPtr pDeviceName = Marshal.StringToHGlobalUni(ddAdapter.DeviceName);
        DEVMODE devmode = new DEVMODE();
        devmode.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));                
        bool bRet = EnumDisplaySettingsEx(pDeviceName, ENUM_CURRENT_SETTINGS, ref devmode, 0);
        if (!bRet)
        {
            devmode.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
            bRet = EnumDisplaySettingsEx(pDeviceName, ENUM_REGISTRY_SETTINGS, ref devmode, 0);
        }
        Console.WriteLine("\tBits Per Pel : {0}", devmode.dmBitsPerPel);
        Console.WriteLine("\tDisplay Frequency : {0} Htz", devmode.dmDisplayFrequency);
        Console.WriteLine("\tLog Pixels : {0}", devmode.dmLogPixels);
        Console.WriteLine("\tPels Width : {0}", devmode.dmPelsWidth);
        Console.WriteLine("\tPels Height : {0}", devmode.dmPelsHeight);
        Console.WriteLine("\tPosition X : {0}", devmode.dmPositionX);
        Console.WriteLine("\tPosition Y : {0}", devmode.dmPositionY);
        Marshal.FreeHGlobal(pDeviceName);
    
        DISPLAY_DEVICE ddMonitor = new DISPLAY_DEVICE();
        ddMonitor.cb = Marshal.SizeOf(typeof(DISPLAY_DEVICE));
        for (uint nMonitor= 0; EnumDisplayDevices(ddAdapter.DeviceName, nMonitor, ref ddMonitor, EDD_GET_DEVICE_INTERFACE_NAME); nMonitor++)
        {
            Console.WriteLine("\t\tMonitor n°{0}", nMonitor + 1);
            Console.WriteLine("\t\tMonitor name : {0}", ddMonitor.DeviceName);
            Console.WriteLine("\t\tMonitor string : {0}", ddMonitor.DeviceString);
            Console.WriteLine("\t\tMonitor ID : {0}", ddMonitor.DeviceID);                   
        }
        Console.WriteLine("");
    }

    with declarations :

                
    [DllImport("User32.dll", SetLastError = true)]
    public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
    
    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAY_DEVICE
    {
        public int cb;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string DeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceString;
        public int StateFlags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceID;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceKey;
    }
    
    public const int EDD_GET_DEVICE_INTERFACE_NAME = 0x00000001;
    
    public const int DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x00000001;
    public const int DISPLAY_DEVICE_MULTI_DRIVER = 0x00000002;
    public const int DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004;
    public const int DISPLAY_DEVICE_MIRRORING_DRIVER = 0x00000008;
    public const int DISPLAY_DEVICE_VGA_COMPATIBLE = 0x00000010;
    public const int DISPLAY_DEVICE_REMOVABLE = 0x00000020;
    public const int DISPLAY_DEVICE_ACC_DRIVER = 0x00000040;
    public const int DISPLAY_DEVICE_MODESPRUNED = 0x08000000;
    public const int DISPLAY_DEVICE_RDPUDD = 0x01000000;
    public const int DISPLAY_DEVICE_REMOTE = 0x04000000;
    public const int DISPLAY_DEVICE_DISCONNECT = 0x02000000;
    public const int DISPLAY_DEVICE_TS_COMPATIBLE = 0x00200000;
    public const int DISPLAY_DEVICE_UNSAFE_MODES_ON = 0x00080000;
    public const int DISPLAY_DEVICE_ACTIVE = 0x00000001;
    public const int DISPLAY_DEVICE_ATTACHED = 0x00000002;
    
    
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool EnumDisplaySettingsEx(IntPtr lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode, int dwFlags);
    
    public const int ENUM_CURRENT_SETTINGS = -1;
    public const int ENUM_REGISTRY_SETTINGS = -2;
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DEVMODE
    {
        private const int CCHDEVICENAME = 32;
        private const int CCHFORMNAME = 32;
    
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
        public string dmDeviceName;
        public short dmSpecVersion;
        public short dmDriverVersion;
        public short dmSize;
        public short dmDriverExtra;
        public int dmFields;
        public int dmPositionX;
        public int dmPositionY;
        public ScreenOrientation dmDisplayOrientation;
        public int dmDisplayFixedOutput;
        public short dmColor;
        public short dmDuplex;
        public short dmYResolution;
        public short dmTTOption;
        public short dmCollate;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
        public string dmFormName;
        public short dmLogPixels;
        public int dmBitsPerPel;
        public int dmPelsWidth;
        public int dmPelsHeight;
        public int dmDisplayFlags;
        public int dmDisplayFrequency;
        public int dmICMMethod;
        public int dmICMIntent;
        public int dmMediaType;
        public int dmDitherType;
        public int dmReserved1;
        public int dmReserved2;
        public int dmPanningWidth;
        public int dmPanningHeight;
    }
    

    Friday, December 13, 2019 2:36 PM
  • Sadly EnumDisplayDevices also does not contain the display numbers. It has the same wrong numbering as e.g. System.Windows.Forms.Screen.AllScreens.
    Tuesday, December 17, 2019 12:34 PM
  • Sadly EnumDisplayDevices also does not contain the display numbers. It has the same wrong numbering as e.g. System.Windows.Forms.Screen.AllScreens.
    And values like positions are not filled ?
    Tuesday, December 17, 2019 12:58 PM
  • Yes positions are filled, so you know the position of the screen, but that is not related to the display number.

    If you look at my initial post, you can see the display 1 is to the far right. If e.g. each display is 100 pixels wide then display 1 would start at 200. Which you can't use to calculate what display number it has. 

    This is an example of what your code outputs regarding a display (and even thought it says display 2 it is actually 1 in Windows):

    Device name : \\.\DISPLAY2
    Device string : NVIDIA GeForce RTX 2070
    Device ID : PCI\VEN_10DE&DEV_1F02&SUBSYS_37311462&REV_A1
    Active : TRUE
    Primary : FALSE
    Attached : TRUE
    Bits Per Pel : 32
    Display Frequency : 59 Htz
    Log Pixels : 96
    Pels Width : 1920
    Pels Height : 1200
    Position X : 1920
    Position Y : 0
    Monitor n°1
    Monitor name : \\.\DISPLAY2\Monitor0
    Monitor string : Generic PnP Monitor
    Monitor ID : \\?\DISPLAY#SAM0CC1#5&3b5a1637&0&UID4357#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}


    Tuesday, December 17, 2019 1:52 PM
  • Hi MEK_DK,

    I noticed "Monitor n°1", is it the number you want?

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, December 18, 2019 1:49 AM
  • Hi Timon.

    You could think that "Monitor n°1" would make sense, but no :-)

    All adapters say "Monitor n°1".

    I really don't know what that info is used for, maybe in some weird scenario where an adapter have multiple monitors.

    Wednesday, December 18, 2019 8:02 AM
  • Hi MEK_DK,

    Try using WMI, maybe it  is helpful.

        public static void Main()
        {
            ConnectionOptions options = new ConnectionOptions();
            string name = Environment.MachineName;
    
            ManagementScope scope = new ManagementScope("\\\\"+name+"\\root\\cimv2", options);
            scope.Connect();
    
            //Query system for Operating System information
            ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_DesktopMonitor");
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
    
            ManagementObjectCollection queryCollection = searcher.Get();
            foreach (ManagementObject m in queryCollection)
            {
                // Display the remote computer information
                Console.WriteLine("Monitor Name     : {0}", m["Name"]);
                Console.WriteLine("Monitor Id     : {0}", m["DeviceID"]);
            }
    
            Console.ReadKey();
        }

    Best Regards,

    Timon



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, December 25, 2019 2:23 AM
  • I have tried using WMI with different Select's and it does not seem to contain the information. Your method only outputs 1 monitor, but even if it showed all of them I doubt it would be correct.
    Monday, January 6, 2020 9:16 AM