question

JeffIbey-2039 avatar image
0 Votes"
JeffIbey-2039 asked JeffIbey-2039 commented

EnumDisplayDevices iDevNum not finding main monitor/secondary monitor

I am trying to draw on any monitor not the main monitor. I use the DISPLAY_DEVICE pointer and run through all 10 ports. I check
if (EnumDisplayDevices(0, [0-9],&DISPLAY_DEVICE,0)!=NULL)
If this is true, that means I found a connected display. I than check the StateFlags for main monitor by checking the third bit set.
If(!(DISPLAY_DEVICE.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))

If it's not set and a display, it's not the main monitor.
If it is set and a display, it is the main monitor.

If I have 2 graphics card, on board GPU and Nvidia GPU on PCIe, and 1 monitor in both cards, I cant find a monitor that is a secondary monitor. All I find is both are set as main based on the state flags. Am I missing something does windows have a main for every GPU/Monitor combo?

windows-api-generalwindows-api-graphics-media
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

XiaopoYang-MSFT avatar image
0 Votes"
XiaopoYang-MSFT answered JeffIbey-2039 commented

Thank for your attached code again!
And according to EnumDisplayDevices function, It is necessary to clarify Display Adapter and Display Device.
You can refer to MADN: Getting Information on a Display Monitor sample or The Following Code(Multi-Byte Character Set) From Internet.

 #include <windows.h>
 #include <stdio.h>
    
 #pragma comment(lib, "user32.lib")
    
 void DumpDevice(const DISPLAY_DEVICE& dd, size_t nSpaceCount )
 {
     printf("%*sDevice Name: %s\n", nSpaceCount, "", dd.DeviceName );
     printf("%*sDevice String: %s\n", nSpaceCount, "", dd.DeviceString );
     printf("%*sState Flags: %x\n", nSpaceCount, "", dd.StateFlags );
     printf("%*sDeviceID: %s\n", nSpaceCount, "", dd.DeviceID );
     printf("%*sDeviceKey: ...%s\n\n", nSpaceCount, "", dd.DeviceKey+42 );
 }
    
 int main()
 {
     DISPLAY_DEVICE dd;
    
     dd.cb = sizeof(DISPLAY_DEVICE);
    
     DWORD deviceNum = 0;
     while( EnumDisplayDevices(NULL, deviceNum, &dd, 0) ){
         DumpDevice( dd, 0 );
         DISPLAY_DEVICE newdd = {0};
         newdd.cb = sizeof(DISPLAY_DEVICE);
         DWORD monitorNum = 0;
         while ( EnumDisplayDevices(dd.DeviceName, monitorNum, &newdd, 0))
         {
             DumpDevice( newdd, 4 );
             monitorNum++;
         }
         puts("");
         deviceNum++;
     }
    
     return 0;
 }




· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I rechecked your documentation, seems someone has updated the thread haha. Based on my old code that is how it was explained, however they have now added these 2 new paragraphs:

To obtain information on a display monitor, first call EnumDisplayDevices with lpDevice set to NULL. Then call EnumDisplayDevices with lpDevice set to DISPLAY_DEVICE.DeviceName from the first call to EnumDisplayDevices and with iDevNum set to zero. Then DISPLAY_DEVICE.DeviceString is the monitor name.

This paragraph answers my current question, thank you guys.

To query all monitor devices associated with an adapter, call EnumDisplayDevices in a loop with lpDevice set to the adapter name, iDevNum set to start at 0, and iDevNum set to increment until the function fails. Note that DISPLAY_DEVICE.DeviceName changes with each call for monitor information, so you must save the adapter name. The function fails when there are no more monitors for the adapter.

Thanks for your support!

0 Votes 0 ·
SongZhu-MSFT avatar image
0 Votes"
SongZhu-MSFT answered JeffIbey-2039 edited

If this is true, that means I found a connected display.

Not so, according to MSDN:

lpDevice

A pointer to the device name. If NULL, function returns information for the display adapter(s) on the machine, based on iDevNum.

So it provides information about the adapter. And you can refer to the remark in the document:

To get information on the display adapter, call EnumDisplayDevices with lpDevice set to NULL. For example, DISPLAY_DEVICE.DeviceString contains the adapter name.

To obtain information on a display monitor, first call EnumDisplayDevices with lpDevice set to NULL. Then call EnumDisplayDevices with lpDevice set to DISPLAY_DEVICE.DeviceName from the first call to EnumDisplayDevices and with iDevNum set to zero. Then DISPLAY_DEVICE.DeviceString is the monitor name.


More reference: EnumDisplayDevices giving two Displays even though I have one


If the answer is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.




· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

lpDevice

A pointer to the device name. If NULL, function returns information for the display adapter(s) on the machine, based on iDevNum.

I am not loking at that value, I set it to 0. What I am looking at is:

iDevNum

An index value that specifies the display device of interest.

The operating system identifies each display device in the current session with an index value. The index values are consecutive integers, starting at 0. If the current session has three display devices, for example, they are specified by the index values 0, 1, and 2.

I Increment this in order to check all adapter sockets. Than I check to see if anything is actually connected to it.

0 Votes 0 ·

According to the documentation:

The primary desktop is on the device. For a system with a single display card, this is always set. For a system with multiple display cards, only one device can have this set.

Could you provide part of the code and screenshots to reproduce the problem to help us understand your problem?



0 Votes 0 ·
 DISPLAY_DEVICE dd;
         ZeroMemory(&dd, sizeof(dd));
         dd.cb = sizeof(dd);
         //check 10 ports
         int displayDevicePort=0;
         for(int i =0; i <10; i++) {
             //check ports are connected
             if(EnumDisplayDevices(0, i, &dd, 0)!=NULL) {
                 //check if not main display
                 if(!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
                     //found extended display break out
                     //EnumDisplayDevices(0, 1, &dd, 0);
                     break;
                 } else {
                     ZeroMemory(&dd, sizeof(dd));
                     dd.cb = sizeof(dd);
                 }
    
             } 
         }


0 Votes 0 ·