locked
How can I retrieve monitor information? RRS feed

  • Question

  • am trying to retrieve the monitor ID's as shown in the Windows display properties (#1, 2... etc), but I can't seem to find a way. I have tried using EnumDisplayMonitors as well as EnumDisplayDevices . They both return something like "\.\DISPLAY1". However, this number doesn't always match the number shown by Windows, especially when 2 video cards are being used to drive 3 or more monitors. Is there an API call I am missing to retrieve this information, or is there a way to get it from the registry or somewhere else? Thanks!

    I have tried these methods:
    Win32: EnumDisplayMonitors , EnumDisplayDevices : Neither of these return monitors that aren't active, and neither one returns the correct IDs.
    WMI: "select * from Win32_DesktopMonitor" doesn't return all the monitors, and there is no ID.
    Registry: I have found the monitors in various locations, none of the places I found have the info I am looking for.

    Any help is much appreciated. :)
    Thursday, April 8, 2010 8:06 PM

All replies

  • Hello

    I used this code to perform the tests:


    #include "stdafx.h"
    #include <windows.h>

    BOOL CALLBACK MyInfoEnumProc(
      HMONITOR hMonitor,
        HDC hdcMonitor,
        LPRECT lprcMonitor,
        LPARAM dwData
    )
    {
        MONITORINFOEX mi;
        ZeroMemory(&mi, sizeof(mi));
        mi.cbSize = sizeof(mi);

        GetMonitorInfo(hMonitor, &mi);
        wprintf(L"DisplayDevice: %s\n", mi.szDevice);
       
        return TRUE;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        printf("\n\n\EnumDisplayDevices\n\n\n");

        DISPLAY_DEVICE dd;
         ZeroMemory(&dd, sizeof(dd));
         dd.cb = sizeof(dd);
         for(int i=0; EnumDisplayDevices(NULL, i, &dd, 0); i++)
         {
             wprintf(L"\n\nDevice %d:", i);
           wprintf(L"\n    DeviceName:   '%s'", dd.DeviceName);
           wprintf(L"\n    DeviceString: '%s'", dd.DeviceString);
           wprintf(L"\n    StateFlags:   %s%s%s%s",
                ((dd.StateFlags &
                  DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ?
                  L"desktop " : L""),
                 ((dd.StateFlags &
                  DISPLAY_DEVICE_PRIMARY_DEVICE     ) ?
                  L"primary " : L""),
                ((dd.StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) ?
                  L"vga "     : L""),
                 ((dd.StateFlags &
                  DISPLAY_DEVICE_MULTI_DRIVER       ) ?
                  L"multi "   : L""),
                ((dd.StateFlags &
                  DISPLAY_DEVICE_MIRRORING_DRIVER   ) ?
                  L"mirror "  : L""));


           // Get more info about the device
           DISPLAY_DEVICE dd2;
           ZeroMemory(&dd2, sizeof(dd2));
           dd2.cb = sizeof(dd2);
           EnumDisplayDevices(dd.DeviceName, 0, &dd2, 0);
           wprintf(L"\n    DeviceID: '%s'", dd2.DeviceID);
           wprintf(L"\n    Monitor Name: '%s'", dd2.DeviceString);
         }

         printf("\n\n\nEnumDisplayMonitors\n\n\n");

         EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0);


     return 0;
    }

    1. when I have only one montor

    it outputs:

    EnumDisplayDevices

    Device 0:
        DeviceName:   '\\.\DISPLAY1'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:   desktop primary
        DeviceID: 'MONITOR\SEC4E42\{4d36e96e-e325-11ce-bfc1-08002be10318}\0000'
        Monitor Name: 'Generic PnP Monitor'

    Device 1:
        DeviceName:   '\\.\DISPLAY2'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:
        DeviceID: ''
        Monitor Name: ''


    <omit some other virtual devices>

    EnumDisplayMonitors

    DisplayDevice: \\.\DISPLAY1

    2. When two monitors are connected to the computer, and only one is enabled, the test application outputs:

    EnumDisplayDevices

    Device 0:
        DeviceName:   '\\.\DISPLAY1'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:   desktop primary
        DeviceID: 'MONITOR\SEC4E42\{4d36e96e-e325-11ce-bfc1-08002be10318}\0000'
        Monitor Name: 'Generic PnP Monitor'

    Device 1:
        DeviceName:   '\\.\DISPLAY2'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:
        DeviceID: 'MONITOR\DEL400C\{4d36e96e-e325-11ce-bfc1-08002be10318}\0003'
        Monitor Name: 'Generic PnP Monitor'


    EnumDisplayMonitors

    DisplayDevice: \\.\DISPLAY1

    3. When two monitors are connected to the computer, and both are enabled, I get this output:

    EnumDisplayDevices

    Device 0:
        DeviceName:   '\\.\DISPLAY1'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:   desktop primary
        DeviceID: 'MONITOR\SEC4E42\{4d36e96e-e325-11ce-bfc1-08002be10318}\0000'
        Monitor Name: 'Generic PnP Monitor'

    Device 1:
        DeviceName:   '\\.\DISPLAY2'
        DeviceString: 'Mobile Intel(R) 4 Series Express Chipset Family'
        StateFlags:   desktop
        DeviceID: 'MONITOR\DEL400C\{4d36e96e-e325-11ce-bfc1-08002be10318}\0003'
        Monitor Name: 'Generic PnP Monitor'


    EnumDisplayMonitors

    DisplayDevice: \\.\DISPLAY1
    DisplayDevice: \\.\DISPLAY2

    As you see from the above test results, StateFlags, DeviceID, and Monitor Name can differentiate the conditions. You can get your requested info based on these differences.


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, April 12, 2010 2:45 AM
  • What I need is the monitor number as shown in the "Screen Resolution" window in Windows 7. These methods work for Windows Vista and earlier, but they don't return the correct order in Windows 7. I was under the impression that MS superceded these functions with the QueryDisplayConfig and related functions for Windows 7?
    Wednesday, April 14, 2010 12:09 AM
  • Hello Jon

    I discussed this with the Shell team. Here is the team's response:

    There is not a supported way to figour out the IDs that you referred to programmatically. It was never a design goal to provide a way for applications to label monitors with the same IDs that the screen resolution control panel uses. What is your application trying to accomplish?


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, April 23, 2010 2:30 AM
  • I have an application that allows users to move windows between monitors. I need a way to reference a monitor, like "Monitor #1". If Windows is exposing a monitor number via the display properties, it's a bit odd that there isn't a way for other applications to retrieve that number. How else can application developers identify monitors and maintain consistency between applications?
    Friday, April 23, 2010 2:05 PM
  • Hello Jon

    You can move windows between monitors with Windows+Shift+Left or Right. You may also consider labeling monitors according to their position, intead of using the control panel's labeling.


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, April 26, 2010 5:19 AM
  • To Jialiang Ge,

     

    With all due respect, I find the answers given to the OP by your team a cop-out and frankly nonsensical.  If indeed your statement:

     

    "It was never a design goal to provide a way for applications to label monitors with the same IDs that the screen resolution control panel uses"

     

    ...is true, then could you please explain what the szDevice member of the MONITORINFOEX structure is useful for?  I too am experiencing a significant issue with windows 7 that was not a problem in Vista or XP.  The issue is that when enumerating display monitors, and in turn calling getMonitorInfo, *sometimes* the szDevice returned matches the 'screen resolution' monitor numbers and sometimes it does not.  This is in fact the same issue that the OP is having.

     

    I find your questioning of the validity of what the OP is trying to accomplish a diversion to the fundamental problem reported by the OP.  It is completely reasonable to expect there to be a way to programmatically associate enumerated displays (and display names) with the screen numbers displayed in 'screen resolution'.  Keep in mind that this was not previously a problem in Vista or XP, and to be proactive, I will detail my situation as to why it is important to be able to programmatically determine which monitors are associated with the monitor numbers as displayed on the 'screen resolution' Windows 7 screen.

     

    My application displays multi-monitor presentations where users typically use 2, 3, or 4 monitors.  These monitors are connected to the computer via any combination of the following: VGA, DVI, HDMI, S-Video.  Users set their resolutions based upon their needs as well as the particular display device they have connected to their video card outputs.  Since my application allows for different output screens to the multiple outputs, it is imperative that my application allow the user to associate what output should be displayed to what display monitor number. Without a reliable way to allow the user to match up their desired output screen to their desired monitor number, significant functionality of my application has been lost on Windows 7.  Please also note that this is not simply a matter of "dragging windows" to each of the monitors.  My application displays outputs and bitmaps fullscreen, so "dragging or snapping windows" (by the user) is a non-option for me.

     

    Since Windows 7 does not (as in previous windows OS's) correctly output the szDevice (I.E. \\.\Display2), there is no way for my application to allow a user to correctly indicate which output they want displayed on which of their display #'s (or to 'remember' these preferences for them, since szDevice is not reliable).

     

    Keep in mind that sometimes the szDevice is correct, and sometimes it is not!  (I.E. sometimes the szDevice correlates with the display numbers on the 'screen resolution' screen, and sometimes it does not.)

     

    I find it difficult to believe that there is no intention in Windows 7 to return an szDevice that correlates with the display #'s on the 'screen resolution' window.  If this were the case, then the documentation on MONITORINFOEX and getMonitorInfo on msdn.com should indicate that the szDevice member is depreciated.  You and I both know that this is a bug, and that the szDevice member is *supposed* to correlate with the display #'s as displayed on the 'screen resolution' window!

     

    Please take this problem more seriously, as there are abundances of valid reasons as to why an application developer might want to programmatically determine the display number of enumerated displays!

     

    I also have filed a bug report with Microsoft on this very issue that has now gone without response for over 5 weeks. (It is bug ID 545217 filed via connect.microsoft.com)

     

    Thank you for re-looking at this issue.

    • Edited by pjkdeveloper Tuesday, May 4, 2010 8:17 AM font too small
    • Proposed as answer by hustsean Monday, February 18, 2013 10:40 AM
    • Unproposed as answer by hustsean Monday, February 18, 2013 10:40 AM
    Tuesday, May 4, 2010 8:14 AM
  • Hi

    I must agree with pjkdeveloper.

    This issue has caused us some serious trouble on several production systems using 1-6 screens where knowing the screen number is essential.

    Please do look into this subject.

    Assaf

     

    Friday, April 1, 2011 6:23 PM
  • It is also a problem for end user when existing application stops to works and it is almost impossible to contact the author of the application. For compatibility purpose, I think that Windows XP/Vista behavior should be kept and there should be a possibility to customize the order wia the registry.

    By the way, it was working properly on Windows 8 developer preview and then stop to works in Windows 8 consumer preview and release preview (end user test on an existing application).

    For permanent installation on a desktop, it might be possible in some case to physical swap connections and never touch connections or display settings but for a laptop the problem is worst when an application would display the prentation on the laptop monitor and the presenter screen on the projector.

    Would running an application Under a virtual machine give more or less control on which monitor are used and in which order. In that case, does the order always matches or are independant?

    It is important to fully document how it works and to be consistent.

    Saturday, June 2, 2012 12:50 PM
  • Just bumping this thread.
    Not having access to this identifier number is causing serious headaches for our application which deals with multi monitor setups.

    Tuesday, October 30, 2012 4:04 PM
  • Have you looked at the monitor classes in the WMI namespace (as opposed to CLI namespace that you used).
     
     
    EG from a command prompt
     
    wmic /NameSpace:\\root\wmi PATH WmiMonitorID get /format:List
     
     

    --
    .
    --
    "Rob Bairos" wrote in message news:2f42322f-7b70-43d4-b569-70dbc47c29c2...

    Just bumping this thread.
    Not having access to this identifier number is causing serious headaches for our application which deals with multi monitor setups.

    Wednesday, October 31, 2012 7:33 AM
  • Hi:Jon Tackabury

    Have you resolve it?

    Can you tell me.

    Thanks


    Monday, February 18, 2013 10:27 AM
  • This question is almost 10 years old, and I'm still having trouble finding an answer. Any chance you have one now?
    Wednesday, April 3, 2019 6:50 PM
  • pjkdeveloper,

    Any chance you have an answer to this question, after almost 10 years?

    Thanks!

    Wednesday, April 3, 2019 6:53 PM
  • This should work.

    std::wstring getMonitorName(HMONITOR monitor) {
    	MONITORINFOEXW info;
    	info.cbSize = sizeof(info);
    	GetMonitorInfoW(monitor, &info);
    
    	UINT32 requiredPaths, requiredModes;
    	GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes);
    	std::vector<DISPLAYCONFIG_PATH_INFO> paths(requiredPaths);
    	std::vector<DISPLAYCONFIG_MODE_INFO> modes(requiredModes);
    	QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes.data(), nullptr);
    
    	for (auto& p : paths) {
    		DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
    		sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
    		sourceName.header.size = sizeof(sourceName);
    		sourceName.header.adapterId = p.sourceInfo.adapterId;
    		sourceName.header.id = p.sourceInfo.id;
    		DisplayConfigGetDeviceInfo(&sourceName.header);
    		if (wcscmp(info.szDevice, sourceName.viewGdiDeviceName) == 0) {
    			DISPLAYCONFIG_TARGET_DEVICE_NAME name;
    			name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
    			name.header.size = sizeof(name);
    			name.header.adapterId = p.sourceInfo.adapterId;
    			name.header.id = p.targetInfo.id;
    			DisplayConfigGetDeviceInfo(&name.header);
    			return std::wstring(name.monitorFriendlyDeviceName);
    		}
    	}
    }


    Wednesday, May 22, 2019 8:59 AM
  • @msqrt Sorry... does not work for me here.

    Combined your function with the OP's program [source here]

    On a Lenovo G50 laptop with one external monitor connected of 2 possible, + built-in display:

    * The Display settings control panel shows the internal as #1 and unnamed; external as #2, name = "LED MONITOR".

    The program's output below:

    EnumDisplayDevices
    
    Device 0:
        DeviceName:   '\\.\DISPLAY1'
        DeviceString: 'Intel(R) HD Graphics 5500'
        StateFlags:   desktop primary
        DeviceID: 'MONITOR\SAN309A\{4d36e96e-e325-11ce-bfc1-08002be10318}\0003'
        Monitor Name: 'Generic PnP Monitor'
    
    Device 1:
        DeviceName:   '\\.\DISPLAY2'
        DeviceString: 'Intel(R) HD Graphics 5500'
        StateFlags:   desktop
        DeviceID: 'MONITOR\LGD0468\{4d36e96e-e325-11ce-bfc1-08002be10318}\0001'
        Monitor Name: 'Generic PnP Monitor'
    
    Device 2:
        DeviceName:   '\\.\DISPLAY3'
        DeviceString: 'Intel(R) HD Graphics 5500'
        StateFlags:
        DeviceID: ''
        Monitor Name: ''
    
    
    EnumDisplayMonitors
    
    
    DisplayDevice: \\.\DISPLAY1
    Name: LED MONITOR
    DisplayDevice: \\.\DISPLAY2
    Name:

    So, DISPLAY1 corresponds to the external monitor which should be #2,

    and DISPLAY2 is the built-in, which should be #1.

    DISPLAY3 is not connected, therefore it does not have DeviceID and any flag.

    Perhaps the numbers assigned in Control panel and WMI are simply indexes in the list of present displays, in ascending order of Device ID. In my case, 0001 ->1 ,0003 ->2

    -- pa





    • Edited by Pavel A Thursday, May 23, 2019 1:55 PM
    Wednesday, May 22, 2019 2:02 PM
  • I agree that it is a nuisance not having a supported function to get this information. I have managed to find what I think is the correct order by doing some registry queries and related processing.

    I believe the order is found in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\monitor\Enum the key labels 0, 1, 2 etc give the order. The key data is unique to each monitor - the trick is to relate that to a physical monitor. Eg DISPLAY\GSM56FE\6&1a2c18c4&0&UID256 the first part is the make and model of the monitor but this is insufficient if there are several of these monitors connected.

    The next task is to enumerate the monitors in WmiMonitorID (you can do this using IID_WbemLocator) this gives the following: Instance, manufacturer, product id and serial number. 

    szInstance "DISPLAY\GSM56FE\6&1a2c18c4&0&UID256_0", szProduct 56FE, szManufacturer GSM, szSerialNo 26969. You need to concatenate the strings to give a unique monitor id of GSM56FE26969. The instance names can be compared with monitor enum data keys obtained above to give the monitor referred to.

    Next you can get the current monitor configuration from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Configuration search for the last subkey to be written for the current data. The key names give the identity of the monitors and order of the subkeys 00, 01, 02 etc. Eg:

    CMN17350_30_07DD_AF+MAG15010_10_07D6_5D+GSM56FE26969_06_07D9_DB+DELA00BU494158D3A4S_21_07D5_C3^FE1C6D1B00F9CA0F129C7AEB916B854D

    The + sign indicates a monitor is extended a * is used for  cloning. The subkeys 00, 01, 02 etc give the size and positions of the monitors in the virtual display. If a monitor is cloned there is one less subkey as it refers to both displays. The first part of the monitor name eg GSM56FE26969 is the same as the monitor id obtained above and so links the screen position to the enumerated monitor order in the first step.

    It works for me with up to 4 monitors.

    Friday, June 12, 2020 2:59 PM
  • @Roger_Bowser: That's a good find but the order is wrong on my setup. I have 4 monitors and 2 of them are reversed compared to the order in the registry. :(
    Tuesday, June 16, 2020 3:19 PM