【发布时间】:2013-08-04 01:28:49
【问题描述】:
我找到了 7 种不同的方法来枚举连接到计算机的监视器。但是所有解决方案都会给出不同的结果(监视器的数量和每个监视器上的信息)。
这些解决方案是:
使用著名的
EnumDisplayDevices使用Windows Management Instrumentation (WMI):
使用以下查询:root\\WMI命名空间中的SELECT * FROM WmiMonitorID。再次使用WMI:
使用新查询:SELECT * FROM Win32_DesktopMonitor位于root\\CIMV2命名空间中。使用Setup API:
首先调用SetupDiGetClassDevs检索设备信息集,然后使用SetupDiEnumDeviceInfo进行迭代使用DirectX Graphics Infrastructure (DXGI)
首先是IDXGIFactory::EnumAdapters,然后是IDXGIAdapter::EnumOutput使用Connecting and Configuring Displays (CCD) APIs:
QueryDisplayConfig(QDC_ALL_PATHS, &numPathArrayElements, pathInfoArray, &numModeInfoArrayElements, modeInfoArray, nullptr);
我试图通过 MSDN 参考准确理解所有这些方法之间的区别,但徒劳无功。
观察
据我观察:
- WmiMonitorID 和 Setup API 查询返回已连接(不一定是活动)显示器的列表。
- Win32_DesktopMonitor WMI 查询返回错误(至少是意外)结果(即使在非活动状态下也仅枚举了 1 个监视器,而桌面位于另一个监视器上)。
- EnumDisplayDevices 返回活动设备列表(除非只有 1 台显示器处于活动状态且连接了其他显示器)
- EnumDisplayMonitors 和 DXGI 查询返回活动监视器列表。
- CCD 似乎是最可靠的方法(提供目标和源之间的所有可能路径)。
问题
使用这些方法(连接显示器列表、已安装显示器列表、活动显示器列表)时,我真正期望的结果是什么?如果我使用镜像显示器或扩展显示器怎么办?如果电脑有多个显卡却没有多个输出怎么办?
Bonus:一些方法(DXGI、EnumDisplayDevices、CCD)使用一种带有Adapter的层次结构- 监视器。但没有给出适配器和监视器之间的相同链接。那么,DXGI 的适配器的定义是什么? CCD?对于 EnumDisplayDevices?
【问题讨论】:
-
我想这里的诀窍是知道它们是否都调用相同的最低级别的 API 并使用它
-
我想正确的做法是问一个更精确的问题,例如“How to enumerate X when doing Y ?”,其中 X 是监视器、物理设备、逻辑设备等。 Y是你的目标。手头有你的目标肯定会让你过滤掉一些可能性。正如您(深入且非常准确的)研究表明的那样,事情并不像您之前想象的那么简单,使用“监视器”和“计算机”等词没有可能的答案。
-
@Cedric Bignon 我不使用 Windows,但你为什么不编写一些使用所有这些方法的测试代码,可能在单独的文件中,然后反汇编二进制文件以查看如果他们进行相同的系统调用?
-
我第二个@tibo。你的问题太开放了。此外,从一个版本的 Windows 到另一个版本也存在差异(某些 DXGI 仅适用于 Windows 8 等)。一个有用的观察结果:.NET 框架(可以被视为 Windows 上的抽象层)定义了完全基于 EnumDisplayMonitors/GetMonitorInfo 的 Screen 类 (System.Windows.Forms.Screen)(这个告诉设备名称)。
-
还有一个:
GetSystemMetrics(SM_CMONITORS)只计算可见的显示监视器。这与 EnumDisplayMonitors 不同,后者枚举与镜像驱动程序关联的可见显示监视器和不可见伪监视器。不可见的伪监视器与用于镜像应用程序绘图以进行远程处理或其他目的的伪设备相关联。