EnumDisplayDevices против WMI Win32_DesktopMonitor, как обнаружить активные мониторы? - PullRequest
9 голосов
/ 08 октября 2008

Для моего текущего проекта C ++ мне нужно определить уникальную строку для каждого монитора, который подключен и активен на большом количестве компьютеров.

Исследования указывают на 2 варианта

  1. Используйте WMI и запросите Win32_DesktopMonitor для всех активных мониторов. Используйте PNPDeviceID для уникальной идентификации мониторов.

  2. Используйте API-интерфейс EnumDisplayDevices и раскройте его, чтобы получить идентификатор устройства.

Меня интересует использование идентификатора устройства для уникальной идентификации модели, поскольку мониторы, использующие драйвер Plug and Play по умолчанию, сообщат об общей строке в качестве имени монитора «Монитор Plug and Play по умолчанию»

У меня возникли проблемы с методом WMI. Кажется, он возвращает только 1 монитор на моем компьютере с ОС Vista, и, глядя на документ, выясняется, что он не работает должным образом на устройствах без WDDM.

EnumDisplayDevices кажется немного проблематичным, если он запускается из фонового сервиса (особенно в Vista). Если он находится в сеансе 0, он не будет возвращать информацию.

  • Кто-нибудь еще должен был сделать нечто подобное (найти уникальную строку модели для всех подключенных активных мониторов?)

  • Какой подход работал лучше всего?

Ответы [ 5 ]

10 голосов
/ 15 октября 2008

Это мой текущий незавершенный код для надежного определения идентификатора устройства монитора.

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++; 
}
2 голосов
/ 19 сентября 2011

Я только что обнаружил, что вы можете запросить 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
1 голос
/ 08 октября 2008

Мы играем с 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 );

Довольно тупой, но работающий.

0 голосов
/ 14 октября 2008

Метод Win32_DesktopMonitor также возвращает только 1 монитор на моем компьютере с Vista. Хотя PnP ID настроен правильно.

Я быстро поиграл с API-интерфейсом EnumDisplayDevices, и, хотя кажется, что он детально обнаруживает детали адаптера (предположительно потому, что большинство людей не оставят его в качестве «Стандартного VGA» надолго), он возвращает только «Plug and Play Monitor "для подключенных мониторов.

Это перекликается с исследованиями, которые я проводил несколько лет назад (пришлось собрать некоторый код, чтобы помочь стереть эти воспоминания).

Это из обычной учетной записи пользователя. Если у вас есть надежный способ заставить EnumDisplayDevices возвращать PnP ID, даже в обычных пользовательских сеансах, я был бы заинтересован - в настоящее время мы выясняем, доступна ли какая-либо из этой информации для драйвера устройства.

Одна вещь, которую вы могли бы сделать, если запуск кода из сеанса # 0 недостаточно надежен, - это посмотреть, сможете ли вы порождать вспомогательный процесс (либо с помощью CreateProcessAsUser, либо с помощью COM с именами активации), который будет выполняться в контекст пользователя.

0 голосов
/ 08 октября 2008

Я никогда не пробовал делать это из службы, но EnumDisplayDevices обычно хорошо работает при запуске от имени пользователя. Я считаю, что службы работают в отдельном (и безголовом) сеансе, что может объяснить проблему, с которой вы там сталкиваетесь.

Не могли бы вы запустить вспомогательную программу из своей службы, выдав себя за учетную запись пользователя, имеющего доступ к дисплеям?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...