I have found 7 different ways to enumerate the monitors attached to the computer. But all solutions give different results (number of the monitors and information on each monitor).
These solutions are:
Using the famous EnumDisplayDevices
Using EnumDisplayMonitors
Using the Windows Management Instrumentation (WMI):
With the following query: SELECT * FROM WmiMonitorID
in the root\\WMI
namespace.
Again using the WMI:
With the new query: SELECT * FROM Win32_DesktopMonitor
in the root\\CIMV2
namespace.
Using the Setup API:
By first calling SetupDiGetClassDevs
to retrieve the device information set then, iterating with SetupDiEnumDeviceInfo
Using the DirectX Graphics Infrastructure (DXGI)
With first IDXGIFactory::EnumAdapters
, then IDXGIAdapter::EnumOutput
Using the Connecting and Configuring Displays (CCD) APIs:
QueryDisplayConfig
(QDC_ALL_PATHS, &numPathArrayElements, pathInfoArray, &numModeInfoArrayElements, modeInfoArray, nullptr);
I've tried to understand precisely the difference between all theses methods with the MSDN reference, in vain.
From what I've observed:
What result should I really expect when using each of these methods (list of connected displays, list of installed displays, list of active displays)? What if I use Mirrored displays or Extended displays? What if the computer has multiple graphics cards without multiple outputs?
Bonus: Some methods (DXGI, EnumDisplayDevices, CCD) use a kind of hierarchy with Adapter-Monitor. But doesn't give the same links between Adapters and Monitors. So, what is the définition of an adapter for DXGI? for CCD? for EnumDisplayDevices?
I don't know all of these API's but I do remember some of them (bad memories) so here's what I can remember and find from poking around in MSDN and playing with wbemtest which I'm surprised I even remember. I recognize that this answer is probably not ALL that you were hoping for.
For the illustrations below (and all of these illustrations are on my Dell Latitude laptop I'm typing this to you on and I have logically two monitors connected to it through the docking station). But, the laptop is closed and the laptop screen is therefore not visible.
If I go into display properties, I see only one screen.
Connected to CIMv2
select * from Win32_DesktopMonitor;
returns two instances.
DesktopMonitor1 is the external display (GenericPNPDisplay) and DesktopMonitor1 is the default monitor (screen).
Connected to root\WMI
select * from WMIMonitorID;
gives me only one instance and that instance is the external monitor (I know this because the manufacturer name is HP). (HWP26CE is the identifier for HP w2408, see here)
Then, there is a difference between display adapters and monitors. EnumDisplayDevices
shows you adapters and EnumDisplayMonitors
shows you the monitors. The former is primarily to just enumerate the adapters but the latter allows you to provide a clipping rectangle and determine which monitors that clipping rectangle happens to land on. This becomes useful when you have multiple active monitors and someone decides to do something that causes a draw that will straddle multiple monitors. You get to specify a callback to EnumDisplayMonitors
and that callback will be invoked with some parameters (if memory serves me correctly one of the parameters was a subset of the specified clipping rectangle that lands on the specified monitor).
I vaguely remember SetupDiEnumDeviceInfo
and I think it gives you the HDEVINFO
for each interface and therefore it would (I believe) give you only one entry on my configuration because I have only one adapter. Then you'd have to do something to go get the SP_DEVINFO_DATA
.
I have never used DirectX and the other API so I'll shut up about those two. Hopefully someone else can pipe up about those two and you may get a complete answer!