9

对于我当前的 C++ 项目,我需要为在大量计算机上连接并处于活动状态的每个监视器检测一个唯一的字符串。

研究指出了两种选择

  1. 使用 WMI 并在 Win32_DesktopMonitor 中查询所有活动监视器。使用 PNPDeviceID 唯一标识监视器。

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

我有兴趣使用设备 ID 来识别唯一的型号,因为使用默认即插即用驱动程序的监视器将报告一个通用字符串作为监视器名称“默认即插即用监视器”

我一直在使用 WMI 方法遇到问题,它似乎只在我的 Vista 机器上返回 1 个显示器,查看文档发现它在非 WDDM 设备上无法正常工作。

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

  • 有没有其他人必须做类似的事情(为所有连接的有源监视器找到唯一的模型字符串?)

  • 哪种方法效果最好?

4

5 回答 5

10

这是我当前用于可靠地检测监控设备 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++; 
}
于 2008-10-14T21:13:30.393 回答
2

我刚刚发现您可以在 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
于 2011-09-19T08:47:08.303 回答
1

我们一直在玩弄 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 );

相当愚蠢,但工作。

于 2008-10-08T16:21:24.817 回答
1

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

我快速使用了 EnumDisplayDevices API,虽然它似乎可靠地发现了适配器的详细信息(大概是因为大多数人不会长时间将其保留为“标准 VGA”),但它只返回“即插即用监视器”对于连接的显示器。

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

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

如果从会话 #0 运行代码不够可靠,您可以做的一件事是查看是否可以生成将在用户上下文中运行的辅助进程(使用 CreateProcessAsUser 或使用带有激活名字对象的 COM)。

于 2008-10-14T15:44:55.953 回答
0

我从未尝试过从服务中执行此操作,但EnumDisplayDevices在以用户身份运行时通常效果很好。我相信服务在一个单独的(无头)会话中运行,这可以解释您在那里看到的问题。

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

于 2008-10-08T15:07:43.360 回答