48

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

这些解决方案是:

  1. 使用著名的EnumDisplayDevices

  2. 使用EnumDisplayMonitors

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

  4. 再次使用WMI :
    使用新查询:SELECT * FROM Win32_DesktopMonitorroot\\CIMV2命名空间中。

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

  6. 使用DirectX 图形基础结构 (DXGI)
    与 first IDXGIFactory::EnumAdapters,然后IDXGIAdapter::EnumOutput

  7. 使用连接和配置显示器 (CCD) API
    QueryDisplayConfig(QDC_ALL_PATHS, &numPathArrayElements, pathInfoArray, &numModeInfoArrayElements, modeInfoArray, nullptr);

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

观察

据我观察:

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

问题

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

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

4

2 回答 2

10

我不知道所有这些 API,但我确实记得其中的一些(糟糕的记忆),所以这就是我能记住的,并通过在 MSDN 中四处寻找和玩 wbemtest 来发现,我很惊讶我什至记得。我认识到这个答案可能不是您所希望的全部。

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

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

在此处输入图像描述

连接到 CIMv2

select * from Win32_DesktopMonitor;

返回两个实例。

在此处输入图像描述

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

连接到 root\WMI

select * from WMIMonitorID;

只给我一个实例,那个实例是外接显示器(我知道这是因为制造商名称是 HP)。(HWP26CE 是 HP w2408 的标识符,见这里

在此处输入图像描述

然后,显示适配器和显示器之间存在差异。EnumDisplayDevices向您展示适配器并向EnumDisplayMonitors您展示显示器。前者主要是枚举适配器,但后者允许您提供一个剪切矩形并确定该剪切矩形恰好落在哪些监视器上。当您有多个活动监视器并且有人决定做一些导致跨越多个监视器的平局时,这将变得很有用。您可以指定一个回调,EnumDisplayMonitors并且将使用一些参数调用该回调(如果内存正确地为我服务,其中一个参数是位于指定监视器上的指定剪切矩形的子集)。

我依稀记得SetupDiEnumDeviceInfo,我认为它为您提供了HDEVINFO每个接口,因此(我相信)它只会在我的配置中为您提供一个条目,因为我只有一个适配器。然后你必须做一些事情才能得到SP_DEVINFO_DATA.

我从来没有使用过 DirectX 和其他 API,所以我对这两个闭嘴。希望其他人可以就这两个问题进行讨论,您可能会得到完整的答案!

于 2013-08-15T23:12:02.833 回答
1

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

或者,如果不相关,您可以随时查看他们的源代码,了解他们如何枚举显示并获取所有相关属性(以及镜像、扩展桌面等)。

于 2013-08-14T13:35:57.630 回答