EnumDisplayDevices vs WMI Win32_DesktopMonitor,如何检测活动监视器? P>对于当前的C++项目,我需要为每个监视器检测一个唯一的字符串,每个监视器在大量的计算机上连接和活动。p>

EnumDisplayDevices vs WMI Win32_DesktopMonitor,如何检测活动监视器? P>对于当前的C++项目,我需要为每个监视器检测一个唯一的字符串,每个监视器在大量的计算机上连接和活动。p>,c++,windows,winapi,wmi,C++,Windows,Winapi,Wmi,研究指出了两种选择 使用WMI并查询Win32_DesktopMonitor中的所有活动监视器。使用PNPDeviceID对监视器进行唯一标识 使用EnumDisplayDevices API,并向下挖掘以获取设备ID 我对使用设备id进行唯一型号标识感兴趣,因为使用默认即插即用驱动程序的监视器将报告一个通用字符串作为监视器名称“默认即插即用监视器” 我遇到了WMI方法的问题,在我的Vista机器上似乎只返回了1个监视器,查看doco后发现它在非WDDM设备上无法正常工作 EnumDisplay

研究指出了两种选择

  • 使用WMI并查询Win32_DesktopMonitor中的所有活动监视器。使用PNPDeviceID对监视器进行唯一标识

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

  • 我对使用设备id进行唯一型号标识感兴趣,因为使用默认即插即用驱动程序的监视器将报告一个通用字符串作为监视器名称“默认即插即用监视器”

    我遇到了WMI方法的问题,在我的Vista机器上似乎只返回了1个监视器,查看doco后发现它在非WDDM设备上无法正常工作

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

    • 是否有其他人必须执行类似操作(为所有连接的活动监视器查找唯一的模型字符串?)

    • 什么方法最有效


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


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

    我们一直在使用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 );
    

    非常愚蠢,但仍在工作。

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

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

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

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


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

    这是我当前正在进行的代码,用于可靠地检测监视器设备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_pPentity for 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
    

    Yerp,CreateProcessAsUser工作正常,前几天我们测试过。它确实引入了相当多的复杂性,但似乎是可靠获取信息的唯一方法。本示例中缺少的一个关键点是忽略镜像设备,而只查看活动设备。看见将发布我当前的工作示例。这只是为我提供了所有监视器的“通用PnP监视器”,我尝试实现了您的代码。我收到一个错误
    标识符DeviceID未定义
    我尝试在msdn上搜索适当的include,但找不到任何单独的DeviceID参数。您能告诉我要识别DeviceID的头文件是什么吗。