Reputation: 1537
I need to get the current display resolution of all monitors attached to the computer.
I can succesfully enum the display devices using the EnumDisplayDevicesA API but for an unknown reason I can't get the current display resolution for the device \\.\DISPLAY2 using the EnumDisplayDevicesA API. Here is the code:
displays = 0;
result = 1;
for (index = 0; result != 0; index++)
{
devices[index].cb = sizeof(DISPLAY_DEVICEA);
result = EnumDisplayDevicesA(NULL, index, &(devices[displays] ), 0);
if (result == 0)
{
break;
}
settings[index].dmSize = sizeof(DEVMODEA);
mode = 0;
// Collect the settings
while(EnumDisplaySettingsA(devices[index].DeviceName, mode, (DEVMODEA *)&(settings[displays] ) ) )
{
mode++;
};
// Read the current settings
result = EnumDisplaySettingsA(devices[index].DeviceName, ENUM_CURRENT_SETTINGS, (DEVMODEA *)&(settings[displays] ) );
if (result != 0)
{
displays++;
}
else
{
result = GetLastError();
printf("Error while readind display settings %d\n", result);
//Skip this device
result = 1;
}
}
Note that this code works flawlessly on some computers while on computers with multiple video cards it fails. For examle it fails on a laptop with an Intel HD Graphicw 630 + Nvidia Quadro M1200 where the active displays are the main laptop display and an exteral display attached through either the HDMI or DP port). More precisely on these computers I can get the correct resolution for the first display device (\\.\DISPLAY1) but on the second display device (\\.\DISPLAY2) the returned width and height is 0.
The EnumDisplaySettingsA API just return 0 as well as the GetLastError API.
What does devices represent ? Are they a monitor attached to a single video card or are they just monitors attached to whatever video card ?
NOTE: Using EnumDisplayMonitors I can get the resolution of all monitors while EnumDisplaySettingsA fails.
Upvotes: 5
Views: 3684
Reputation: 119
Could it be that more than two devices can be obtained by iterating over EnumDisplayDevices?
For me there were like 7 \.\DISPLAYX entries, even though I only have the Laptop Display and two external Monitors.
And when calling EnumDisplaySettings with a not connected Display, the results are like in your case 0. For me DISPLAY1, DISPLAY4 and DISPLAY5 were the ones I needed to use.
Upvotes: 3
Reputation: 1537
The problem is not related to the windows API nor related to the casting. The casting is not needed so I removed it.
This is caused by a wrong usage of the variables in the code. As I said I only want the current resolution of each monitor and on every index of both devices
and settings
structures I only want data related to active displays. This is ensured by the usage of the displays
variable which is only incremented when the device has readable settings. Conversely the index
variable should be incremented to each loop until the EnumEnumDisplayDevicesA
fails.
Unfortunately I used index
also for initializing the structure and passing the device name to EnumDisplaySettingsA
. My bad. So I was filling the devices structure using the devices[displays]
statement while the structure passed to EnumDisplaySettingsA
was devices[index]
. In other words the incorrect name was passed to the API ant this is the reason while it was failing. On some computers it was working because the active monitor were the first but as soon as the DISPLAY1 or DISPALY2 was not connected the application would behave incorrectly.
This is the correct code:
displays = 0;
result = 1;
for (index = 0; result != 0; index++)
{
devices[displays].cb = sizeof(DISPLAY_DEVICEA);
result = EnumDisplayDevicesA(NULL, index, &(devices[displays] ), 0);
if (result == 0)
{
break;
}
settings[displays].dmSize = sizeof(DEVMODEA);
mode = 0;
// Cache the settings
EnumDisplaySettingsA(devices[displays].DeviceName, 0, &(settings[displays] ) )
// Read the current settings
result = EnumDisplaySettingsA(devices[displays].DeviceName, ENUM_CURRENT_SETTINGS, &(settings[displays] ) );
if (result != 0)
{
displays++;
}
else
{
result = GetLastError();
printf("Error while readind display settings %d\n", result);
//Skip this device
result = 1;
}
Upvotes: 3
Reputation: 31599
(DEVMODEA*)&(settings[displays])
The fact that you are using a cast suggests settings
is defined incorrectly, and cast is used to hide the problem. If you have declared, for example, DEVMODEA *settings = malloc(count * sizeof(DEVMODEA))
then casting should not be necessary.
You should simply use Unicode functions as recommended by Microsoft. If you need to print ANSI, then use WideCharToMultiByte
to convert Unicode to ANSI.
Moreover, you are overwriting settings[index]
in the code below:
while(EnumDisplaySettingsA(devices[index].DeviceName, mode, (DEVMODEA *)&(settings[displays] ) ) ) mode++; result = EnumDisplaySettingsA(devices[index].DeviceName, ENUM_CURRENT_SETTINGS, (DEVMODEA *)&(settings[displays] ) );
Note that the second call to EnumDisplaySettingsA
uses ENUM_CURRENT_SETTINGS
, this call will never fail and may cause problems in your loop. It will also overwrite the previous value for settings[displays]
Try the code below to see if there is a difference.
int main()
{
DISPLAY_DEVICE device = { 0 };
device.cb = sizeof(DISPLAY_DEVICE);
for(int index = 0;; index++)
{
if(!EnumDisplayDevices(NULL, index, &device, EDD_GET_DEVICE_INTERFACE_NAME))
break;
#ifdef UNICODE
wprintf(L"%s\n", device.DeviceName);
#else
printf("%s\n", device.DeviceName);
#endif
DEVMODE devmode = { 0 };
devmode.dmSize = sizeof(DEVMODE);
for(int modes = 0;; modes++)
{
if(!EnumDisplaySettings(device.DeviceName, modes, &devmode))
break;
printf("%d %d %d\n",
devmode.dmPelsWidth,
devmode.dmPelsHeight,
devmode.dmDisplayFrequency);
}
}
return 0;
}
Or read current resolution for each monitor
int main()
{
int count = 0;
DISPLAY_DEVICE temp = { 0 };
temp.cb = sizeof(DISPLAY_DEVICE);
while(EnumDisplayDevices(NULL, count, &temp, EDD_GET_DEVICE_INTERFACE_NAME))
count++;
DEVMODE *settings = malloc(count * sizeof(DEVMODE));
DISPLAY_DEVICE *devices = malloc(count * sizeof(DISPLAY_DEVICE));
for (int index = 0; index < count; index++)
{
memset(&devices[index], 0, sizeof(DISPLAY_DEVICE));
memset(&settings[index], 0, sizeof(DEVMODE));
devices[index].cb = sizeof(DISPLAY_DEVICE);
settings[index].dmSize = sizeof(DEVMODE);
if(!EnumDisplayDevices(NULL, index, &devices[index], EDD_GET_DEVICE_INTERFACE_NAME))
break;
if(!EnumDisplaySettings(devices[index].DeviceName, ENUM_CURRENT_SETTINGS, &settings[index]))
break;
}
for(int index = 0; index < count; index++)
{
#ifdef UNICODE
wprintf(L"%s ", devices[index].DeviceName);
#else
printf("%s ", devices[index].DeviceName);
#endif
printf("%d %d %d\n",
settings[index].dmPelsWidth,
settings[index].dmPelsHeight,
settings[index].dmDisplayFrequency);
}
return 0;
}
Upvotes: 3