EnumDisplayDevices vs WMI Win32_DesktopMonitor, comment détecter les moniteurs actifs?

StackOverflow https://stackoverflow.com/questions/181064

  •  05-07-2019
  •  | 
  •  

Question

Pour mon projet C ++ actuel, je dois détecter une chaîne unique pour chaque moniteur connecté et actif sur un grand nombre d'ordinateurs.

La recherche a mis en évidence 2 options

  1. Utilisez WMI et interrogez Win32_DesktopMonitor pour tous les moniteurs actifs. Utilisez le PNPDeviceID pour l'identification unique des moniteurs.

  2. Utilisez l'API EnumDisplayDevices et creusez pour obtenir l'ID de périphérique.

Je voudrais utiliser l'ID de périphérique pour l'identification de modèle unique car les moniteurs utilisant le pilote plug-and-play par défaut rapporteront une chaîne générique sous le nom du moniteur "moniteur plug-and-play par défaut".

J'ai eu des problèmes avec la méthode WMI, il semble ne renvoyer qu'un moniteur sur mon ordinateur Vista. En regardant la documentation, il s'avère que cela ne fonctionne pas comme prévu sur les périphériques non WDDM.

Les EnumDisplayDevices semblent être un peu problématiques à prendre en charge s’ils fonctionnent à partir d’un service en arrière-plan (en particulier sous Vista). S'il est en session 0, il ne renverra aucune information.

  • Quelqu'un d'autre a-t-il déjà dû faire quelque chose de similaire (rechercher une chaîne de modèle unique pour tous les moniteurs actifs connectés?)

  • Quelle approche a fonctionné le mieux?

Était-ce utile?

La solution

Ceci est mon code de travail en cours actuel pour détecter de manière fiable l'identifiant du périphérique de surveillance.

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++; 
}

Autres conseils

Je viens de découvrir que vous pouvez interroger Win32_PnPEntity pour service = "moniteur", et tous les moniteurs seront renvoyés.

Résultats sur ma machine:

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

Nous avons utilisé EnumDisplayDevices afin de détecter si le fabricant actuel de la carte vidéo est NVIDIA. Ce n'est pas la même chose, mais peut-être que ça aiderait. Notre pièce ressemblait à ceci:

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 );

Assez stupide, mais travaille.

Je n'ai jamais essayé de le faire à partir d'un service, mais EnumDisplayDevices fonctionne généralement bien lorsqu'il est exécuté en tant qu'utilisateur. Je pense que les services fonctionnent dans une session séparée (et sans tête), ce qui pourrait expliquer le problème que vous rencontrez ici.

Pourriez-vous exécuter un programme d'assistance à partir de votre service, empruntant l'identité d'un compte d'utilisateur ayant accès aux affichages?

La méthode Win32_DesktopMonitor ne renvoie également qu’un moniteur sur mon ordinateur Vista. L’ID PnP semble être correctement défini, cependant.

J'ai eu un jeu rapide avec l'API EnumDisplayDevices et, bien qu'il semble découvrir les détails de l'adaptateur de manière fiable (probablement parce que la plupart des gens ne le laisseront pas sous la forme "Standard VGA", il ne fera que renvoyer " Moniteur Plug-and-Play " pour les moniteurs connectés.

Cela fait écho à la recherche que j’ai effectuée il ya plusieurs années (il a fallu rassembler du code pour aider à dépoussiérer ces souvenirs).

Cela provient d'un compte d'utilisateur normal. Si vous disposez d'un moyen fiable de renvoyer l'ID PnP à EnumDisplayDevices, même lors de sessions utilisateur normales, je serais intéressé - nous examinons actuellement si certaines de ces informations sont disponibles pour un pilote de périphérique.

Si le code de la session n ° 0 n’est pas assez fiable, vous pouvez également voir si vous pouvez générer un processus auxiliaire (soit en utilisant CreateProcessAsUser, soit en utilisant COM avec des monikers d’activation). contexte de l'utilisateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top