2008-10-08 5 views
9

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.EnumDisplayDevices vs WMI Win32_DesktopMonitor, comment détecter les moniteurs actifs?

La recherche a mis en évidence 2 options

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

  2. Utilisez l'API EnumDisplayDevices et décompressez pour obtenir l'ID du périphérique.

Je suis intéressé à utiliser l'identifiant de dispositif d'identification de modèle unique parce que les moniteurs en utilisant la prise par défaut et jouer pilote rapportera une chaîne générique comme le nom du moniteur « prise par défaut et-play »

I J'ai eu des problèmes avec la méthode WMI, il semble que je retourne seulement 1 moniteur sur ma machine Vista, en regardant le doco, il s'avère qu'il ne fonctionne pas comme prévu sur les périphériques non WDDM. Le EnumDisplayDevices semble être un peu problématique à démarrer quand il fonctionne à partir d'un service d'arrière-plan (en particulier sur Vista), Si c'est en session 0, il ne renverra aucune information.

  • A quelqu'un d'autre a dû faire quelque chose de similaire (trouver chaîne de modèle unique pour tous les moniteurs actifs connectés?)

  • Quelle approche a le mieux fonctionné?

Répondre

10

Il s'agit de mon code de travail en cours pour la détection fiable de l'ID 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++; 
} 
+0

J'ai essayé d'implémenter votre code. J'obtiens une erreur 'Identifiant DeviceID is undefined' J'ai essayé de rechercher sur msdn un include approprié mais je n'ai pas trouvé de paramètre DeviceID séparé. Pouvez-vous s'il vous plaît me dire quel fichier d'en-tête à inclure pour DeviceID à identifier. – newbie2015

0

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

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

1

Nous avons été en train de jouer avec EnumDisplayDevices afin de détecter si le fabricant actuel de cartes vidéo est NVIDIA. Ce n'est pas la même chose, mais peut-être que cela 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 fonctionnant.

+0

Une chose qui est critique et manque de cet échantillon est ignorant des dispositifs de miroir et ne regardant que des dispositifs actifs. Voir http://msdn.microsoft.com/en-us/library/aa477606.aspx. Va poster mon échantillon de travail actuel. –

0

La méthode Win32_DesktopMonitor renvoie également 1 moniteur sur ma machine Vista. L'ID PnP semble être défini correctement, cependant.

J'ai eu un jeu rapide avec l'API EnumDisplayDevices, et alors qu'il semble découvrir les détails de l'adaptateur de manière fiable (sans doute parce que la plupart des gens ne le laisseront pas comme "VGA standard"), et Play Monitor "pour les moniteurs connectés. Cela fait écho aux recherches que j'ai faites dans ce domaine il y a plusieurs années (j'ai dû mettre du code ensemble pour aider à épousseter ces souvenirs).

Ceci provient d'un compte utilisateur normal. Si vous avez un moyen fiable d'obtenir EnumDisplayDevices pour renvoyer l'ID PnP, même dans les sessions utilisateur normales, cela m'intéresserait - nous étudions actuellement si l'une de ces informations est disponible pour un pilote de périphérique.Une chose que vous pourriez faire, si l'exécution du code de la session n ° 0 n'est pas assez fiable, est de voir si vous pouvez générer un processus d'assistance (soit en utilisant CreateProcessAsUser ou en utilisant COM avec des monikers d'activation) le contexte de l'utilisateur.

+0

Yerp, CreateProcessAsUser fonctionne très bien, nous l'avons testé l'autre jour. Il introduit beaucoup de complexité mais semble être le seul moyen d'obtenir cette information de manière fiable. –

2

Je viens de découvrir que vous pouvez interroger Win32_PnPEntity service = « surveiller », et il retournera tous les moniteurs.

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 
+1

Cela me donne juste "Generic PnP Monitor" pour tous les moniteurs – acron

Questions connexes