EnumDisplayDevices与WMI Win32_DesktopMonitor,如何检测活动监视器?

对于我当前的C ++项目,我需要为大量计算机上连接并激活的每个监视器检测唯一的string。

研究指出了2个select

  1. 使用WMI并查询所有活动监视器的Win32_DesktopMonitor。 使用PNPDeviceID来唯一标识显示器。

  2. 使用EnumDisplayDevices API,并挖掘获取设备ID。

我有兴趣使用设备ID进行独特的模型识别,因为使用默认即插即用驱动程序的监视器将报告一个通用string作为监视器名称“默认即插即用监视器”

我一直在遇到与WMI方法有关的问题,它似乎只在我的Vista机器上返回1个显示器,看着doco,结果表明它在非WDDM设备上无法正常工作。

EnumDisplayDevices在从后台服务(尤其是Vista)运行时似乎有点麻烦,如果它在会话0中,它将不返回任何信息。

  • 有没有其他人不得不做类似的事情(find所有连接的主动显示器独特的模型string?)

  • 哪种方法效果最好?

这是我目前正在工作的代码,用于可靠地检测监视器设备ID。

CString DeviceID; DISPLAY_DEVICE dd; dd.cb = sizeof(dd); DWORD dev = 0; // device index int id = 1; // monitor number, as used by Display Properties > Settings while (EnumDisplayDevices(0, dev, &dd, 0)) { DISPLAY_DEVICE ddMon; ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); DWORD devMon = 0; while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0)) { if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) { DeviceID.Format (L"%s", ddMon.DeviceID); DeviceID = DeviceID.Mid (8, DeviceID.Find (L"\\", 9) - 8); } devMon++; ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); } ZeroMemory(&dd, sizeof(dd)); dd.cb = sizeof(dd); dev++; } 

我刚刚发现你可以查询Win32_PnPEntity的service =“monitor”,它会返回所有的监视器。

在我的机器上的结果:

 select * from Win32_PnPEntity where service="monitor" Availability | Caption | ClassGuid | CompatibleID | ConfigManagerErrorCode | ConfigManagerUserConfig | CreationClassName | Description | DeviceID | ErrorCleared | ErrorDescription | HardwareID | InstallDate | LastErrorCode | Manufacturer | Name | PNPDeviceID | PowerManagementCapabilities | PowerManagementSupported | Service | Status | StatusInfo | SystemCreationClassName | SystemName | Dell 2007FP (Digital) | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0] | 0 | False | Win32_PnPEntity | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 | | | array[0..0] | | | Dell Inc. | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 | | | monitor | OK | | Win32_ComputerSystem | 8HVS05J | Dell ST2320L_Digital | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0] | 0 | False | Win32_PnPEntity | Dell ST2320L_Digital | DISPLAY\DELF023\5&4F61016&0&UID256 | | | array[0..0] | | | Dell Inc. | Dell ST2320L_Digital | DISPLAY\DELF023\5&4F61016&0&UID256 | | | monitor | OK | | Win32_ComputerSystem | 8HVS05J 

我们一直在玩EnumDisplayDevices,以检测当前的视频卡制造商是否是NVIDIA。 这是不一样的,但也许会有所帮助。 我们的作品看起来像这样:

 int disp_num = 0; BOOL res = TRUE; do { DISPLAY_DEVICE disp_dev_info; ZeroMemory( &disp_dev_info, sizeof(DISPLAY_DEVICE) ); disp_dev_info.cb = sizeof(DISPLAY_DEVICE); res = EnumDisplayDevices( 0, disp_num++, &disp_dev_info, 0x00000001 ); if(res && disp_dev_info.DeviceString[0]!=0 && disp_dev_info.DeviceString[0]=='N' && disp_dev_info.DeviceString[1]!=0 && disp_dev_info.DeviceString[1]=='V' && disp_dev_info.DeviceString[2]!=0 && disp_dev_info.DeviceString[2]=='I' && disp_dev_info.DeviceString[3]!=0 && disp_dev_info.DeviceString[3]=='D' && disp_dev_info.DeviceString[4]!=0 && disp_dev_info.DeviceString[4]=='I' && disp_dev_info.DeviceString[5]!=0 && disp_dev_info.DeviceString[5]=='A'){ isNVidia = true; } int x = 0; }while( res != FALSE ); 

很笨,但工作。

我从来没有尝试EnumDisplayDevices一个服务,但EnumDisplayDevices通常作为一个用户运行良好。 我相信服务在单独的(无头的)会话中运行,这可以解释您在那里看到的问题。

你可以从你的服务中运行一个帮手程序,模仿一个可以访问显示器的用户帐户吗?

Win32_DesktopMonitor方法也只在我的Vista机器上返回1个监视器。 虽然,PnP ID似乎设置正确。

我已经和EnumDisplayDevices API一起玩过了,尽管它似乎可靠地发现了适配器细节(大概是因为大多数人不会把它作为“标准VGA”),但它只返回“即插即用监视器”为连接的显示器。

这与我几年前所做的研究相呼应(必须把一些代码放在一起,以帮助清除那些记忆)。

这是来自一个正常的用户帐户。 如果你有一个可靠的方法让EnumDisplayDevices返回即插即用ID,即使在正常的用户会话中,我也会感兴趣 – 我们目前正在调查这些信息是否可用于设备驱动程序。

你可以做的一件事是,如果从session#0运行代码是不够可靠的,那就是看你是否可以在用户的​​上下文中产生一个辅助进程(使用CreateProcessAsUser或者使用COM与激活标记)。