2011-03-11 20 views
10

He estado escribiendo un código que detecta añadir y eliminación de dispositivos USB, y he utilizado el siguiente código de WMI para registrar las notificaciones de cambio de dispositivo:El uso de WMI para identificar qué dispositivo causó una Win32_DeviceChangeEvent

watcher = new ManagementEventWatcher(query); 
watcher.EventArrived += new EventArrivedEventHandler(DeviceChangeEventReceived); 
watcher.Start(); 

este es el código del controlador:

void DeviceChangeEventReceived(object sender, EventArrivedEventArgs e) 
{ 
    foreach (PropertyData pd in e.NewEvent.Properties) 
    { 
     Log.Debug("\t" + pd.Name + ":" + pd.Value + "\t" + pd.Value.GetType()); 
    } 
} 

esto es grande y todo, funciona para cualquier dispositivo USB enchufo o eliminar del sistema. El problema que estoy teniendo es, ¿cómo identifico el dispositivo específicamente que causó los eventos?

En otra parte de mi programa, guardo una lista de los dispositivos actualmente conectados que más me interesan, así que si aparece un evento eliminado por el dispositivo, puedo verificar esa lista en WMI usando "select * from Win32_PnPEntity "o alguna otra consulta similar. PERO, esta es una forma muy incorrecta e incómoda de identificar el dispositivo que se eliminó. El problema adicional es que no tengo forma de decir con precisión qué dispositivo se agregó, a menos que almacene en caché toda la lista de Win32_PnPEntity antes de tiempo, y realice comparaciones/validaciones realmente alocadas.

¿Me falta algo obvio aquí? ¿Cómo asocio los eventos de cambio de dispositivo a un dispositivo específico?

ACTUALIZACIÓN: Todavía no he encontrado una solución ideal para este problema, pero lo que estoy haciendo es mantener una lista de los dispositivos actualmente conectados (que me interesan) en la memoria, y cada vez que un evento se maneja (ver arriba), consulto el Win32_PnPEntity para ver si los dispositivos que he almacenado en mi lista de dispositivos conectados todavía están conectados. Esta es una solución subóptima, porque parece extraño que no pueda obtener ninguna información específica de identificación del dispositivo del evento que indique "evento de cambio del dispositivo". Parece MUY extraño, que esta información no está disponible. suspiro

Respuesta

15

bien, así que después de un poco más investigación y experimentación, he descubierto que tengo que utilizar una consulta WMI diferente con el fin de resolver mi problema, que consiste en asociar un evento de cambio de dispositivo con un dispositivo específico. En este caso, necesito encontrar lo que parece ser referido convencionalmente en WMI como "TargetInstance".

Por lo tanto, se utiliza el siguiente código de consulta WMI en lugar

  ManagementEventWatcher watcher; 
      string queryStr = 
       "SELECT * FROM __InstanceCreationEvent " + 
       "WITHIN 2 " 
       + "WHERE TargetInstance ISA 'Win32_PnPEntity'" 

      watcher = new ManagementEventWatcher(queryStr); 
      watcher.EventArrived += new EventArrivedEventHandler(DeviceChangeEventReceived); 
      watcher.Start(); 

Así que la diferencia aquí es, que el __InstanceCreationEvent tiene una propiedad llamada "TargetInstance", que es exactamente lo que estaba buscando. Echo la propiedad TargetInstance a un objeto ManagementBaseObject (que es del tipo "Win32_PnPEntity" (según la cláusula ISA en la consulta anterior), y ¡Voila! Obtengo el dispositivo específico que se creó.

Todavía me confunde un poco a cómo mi consulta original "Seleccionar * de Win32_DeviceChangeEvent" sería útil para cualquier persona, ya que no se proporciona información adicional después de que se active una notificación de evento genérico. De cualquier forma, esta nueva consulta es una solución significativamente más limpia para mi problema. bastante potente, pero encontrar la consulta correcta para usar puede ser complicado y requiere algo de experimentación.

+1

Esta buena respuesta sí funciona, pero desafortunadamente es una desventaja. Los usuarios deben saber que esta es una consulta ** _ polling _ ** (la sugerencia es "dentro de 2", y "dentro" no es una opción l para esta consulta). Requiere que la CPU haga sondeos constantemente, y esto se puede ver como una carga significativa de la CPU (en mi prueba, aproximadamente ~ 5% en un sistema de cuatro núcleos, realmente alrededor del 20% de un solo núcleo, con dos consultas usando "dentro de 1 ") en el servicio WmiPrvSE.exe. Estos eventos también se producen, como es lógico, unos 1-2 segundos después del Win32_DeviceChangeEvent correspondiente, por lo que hay un retraso significativo en la generación de informes. – dale

Cuestiones relacionadas