枚举计算机上的监视器

时间:2013-08-02 17:15:23

标签: c++ windows gdi dxgi

我找到了7种不同的方法来枚举连接到计算机的显示器。但是所有解决方案都会给出不同的结果(监视器的数量和每个监视器上的信息)。

这些解决方案是:

  1. 使用着名的EnumDisplayDevices

  2. 使用EnumDisplayMonitors

  3. 使用Windows Management Instrumentation (WMI)
    使用以下查询:SELECT * FROM WmiMonitorID命名空间中的root\\WMI

  4. 再次使用WMI
    使用SELECT * FROM Win32_DesktopMonitor命名空间中的新查询root\\CIMV2

  5. 使用Setup API
    首先调用SetupDiGetClassDevs检索设备信息集,然后使用SetupDiEnumDeviceInfo

  6. 进行迭代
  7. 使用DirectX Graphics Infrastructure (DXGI)
    首先是IDXGIFactory::EnumAdapters,然后是IDXGIAdapter::EnumOutput

  8. 使用Connecting and Configuring Displays (CCD) APIs
    QueryDisplayConfig (QDC_ALL_PATHS, &numPathArrayElements, pathInfoArray, &numModeInfoArrayElements, modeInfoArray, nullptr);

  9. 我试图准确理解所有这些方法与MSDN参考之间的区别,但是徒劳无功。

    观察

    从我观察到的情况来看:

    • WmiMonitorID Setup API 查询返回已连接(不一定是活动)显示的列表。
    • Win32_DesktopMonitor WMI 查询返回错误的(至少是意外的)结果(即使在非活动状态和另一台监视器上的桌面上,也只会枚举1个监视器)。
    • EnumDisplayDevices 返回活动设备列表(除非只有1台显示器处于活动状态且其他显示器已连接)
    • EnumDisplayMonitors DXGI 查询返回活动监视器列表。
    • CCD 似乎是最可靠的方法(在目标和来源之间提供所有可能的路径)。

    问题

    使用这些方法时,我应该真正期待什么结果(连接的显示列表,已安装的显示列表,活动显示列表)?如果我使用镜像显示器或扩展显示器怎么办?如果计算机有多个没有多个输出的图形卡怎么办?

    额外奖励:某些方法( DXGI EnumDisplayDevices CCD )使用适配器的一种层次结构 - 监视器。但是在Adapters和Monitors之间没有给出相同的链接。那么, DXGI 的适配器的定义是什么?对于 CCD ?对于 EnumDisplayDevices

2 个答案:

答案 0 :(得分:10)

我不知道所有这些API,但我确实记得其中的一些(糟糕的回忆)所以这里是我记得并在MSDN中探索并使用wbemtest进行查找的内容我甚至还记得,我感到很惊讶。我认识到这个答案可能不是你希望的 ALL

对于下面的插图(所有这些插图都在我的戴尔Latitude笔记本电脑上,我打算给你打字,我逻辑上有两台显示器通过扩展坞连接到它)。但是,笔记本电脑已关闭,因此笔记本电脑屏幕不可见。

如果我进入显示属性,我只看到一个屏幕。

enter image description here

连接到CIMv2

select * from Win32_DesktopMonitor;

返回两个实例。

enter image description here

DesktopMonitor1是外部显示器(GenericPNPDisplay),DesktopMonitor1是默认监视器(屏幕)。

连接到root \ WMI

select * from WMIMonitorID;

只给我一个实例,该实例是外部监视器(我知道这是因为制造商名称是HP)。 (HWP26CE是HP w2408的标识符,请参阅here

enter image description here

然后,显示适配器和显示器之间存在差异。 EnumDisplayDevices显示适配器,EnumDisplayMonitors显示监视器。前者主要是枚举适配器,但后者允许您提供剪切矩​​形并确定剪切矩形碰巧落在哪些监视器上。当您有多个活动监视器并且有人决定执行某些操作会导致跨越多个监视器的绘制时,这将变得非常有用。您可以指定回调到EnumDisplayMonitors,并且将使用某些参数调用回调(如果内存正确地为我提供了参数之一,则指定剪切矩形的子集落在指定的监视器上)。

我依稀记得SetupDiEnumDeviceInfo,我认为它为每个接口提供了HDEVINFO,因此它(我相信)只给我一个条目,因为我只有一个适配器。然后你必须做点什么才能获得SP_DEVINFO_DATA

我从未使用过DirectX和其他API,所以我会关闭这两个API。希望其他人可以了解这两个,你可能得到一个完整的答案!

答案 1 :(得分:1)

如果与您的情况相关,在使用Qt 5.x时,您可以使用QGuiApplication::screens()方法(http://qt-project.org/doc/qt-5.1/qtgui/qguiapplication.html#screens)枚举所有显示。

如果它不相关,您可以随时查看其源代码,它们如何枚举显示并获取所有相关属性(还有关于镜像,扩展桌面等)。