Использование WMI для определения того, какое устройство вызвало Win32_DeviceChangeEvent
Я писал код, который обнаруживает добавление и удаление USB-устройств, и использовал следующий код WMI для регистрации уведомлений об изменении устройства:
watcher = new ManagementEventWatcher(query);
watcher.EventArrived += new EventArrivedEventHandler(DeviceChangeEventReceived);
watcher.Start();
Это код обработчика:
void DeviceChangeEventReceived(object sender, EventArrivedEventArgs e)
{
foreach (PropertyData pd in e.NewEvent.Properties)
{
Log.Debug("\t" + pd.Name + ":" + pd.Value + "\t" + pd.Value.GetType());
}
}
Это прекрасно, и все, это работает для любого USB-устройства, которое я подключаю или удаляю из системы. Проблема, с которой я сталкиваюсь, заключается в том, как определить устройство, конкретно вызвавшее события?
В другом месте в моей программе я храню список подключенных в данный момент устройств, которые меня больше всего интересуют, поэтому, если происходит событие удаления устройства, я могу проверить этот список по WMI, используя "select * from Win32_PnPEntity" или другие аналогичный запрос. НО, это очень неточный и громоздкий способ идентификации устройства, которое было удалено. Проблема в том, что я не могу точно сказать, какое устройство было добавлено, если я заранее не кеширую весь список Win32_PnPEntity и не сделаю действительно сумасшедшие сравнения / проверки.
Я что-то упускаю здесь очевидное? Как связать события смены устройства с конкретным устройством?
ОБНОВЛЕНИЕ: я все еще не нашел идеального решения этой проблемы, но я делаю, чтобы поддерживать список подключенных в данный момент устройств (которые меня интересуют) в памяти, и каждый раз, когда событие обрабатывается (см. выше), я запрашиваю Win32_PnPEntity, чтобы узнать, все ли еще подключены устройства, которые я сохранил в моем списке подключенных устройств. Это неоптимальное решение, потому что мне кажется странным, что я не могу получить какую-либо конкретную идентификационную информацию устройства из события, которое указывает "событие изменения устройства". ОЧЕНЬ странно, что эта информация недоступна. вздох
1 ответ
Итак, после некоторого дальнейшего исследования и экспериментов я обнаружил, что мне нужно использовать другой запрос WMI для решения моей проблемы, а именно связать событие смены устройства с конкретным устройством. В этом случае мне нужно найти то, что в WMI обычно называют "TargetInstance".
Итак, вместо этого я использовал следующий код запроса WMI
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();
Таким образом, разница здесь в том, что __InstanceCreationEvent имеет свойство с именем "TargetInstance", которое именно то, что я искал. Я привел свойство TargetInstance к ManagementBaseObject (который имеет тип "Win32_PnPEntity" (согласно предложению ISA в запросе выше), и вуаля! Я получаю конкретное устройство, которое было создано.
Это все еще немного сбивает меня с толку относительно того, как мой оригинальный запрос "Select * from Win32_DeviceChangeEvent" будет вообще полезен для всех, так как никакой дополнительной информации после генерации общего уведомления о событии не предоставляется. В любом случае, этот новый запрос является значительно более чистым решением моей проблемы. WMI кажется довольно мощным, но найти правильный запрос для использования может быть сложно, и требует некоторых экспериментов.