Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using WMI to identify which device caused a Win32_DeviceChangeEvent

Tags:

c#

wmi

I have been writing some code that detects add and removal of USB devices, and I've used the following WMI code to register for device change notifications:

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

This is the handler code:

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

This is great and all, it works for any USB device I plug in or remove from the system. The problem that I'm having is, how do I identify the the device specifically that caused the events?

Elsewhere in my program, I'm keeping a list of currently connected devices that I'm most interested in, so if a device-removed event comes through, I can check that list against WMI using "select * from Win32_PnPEntity" or some other similar query. BUT, this is a very inaccurate and cumbersome way of identifying the device that was removed. The added problem is, I have no way of accurately telling what device was added, unless I cache the entire list of Win32_PnPEntity ahead of time, and do really crazy comparisons/validations.

Am I missing something obvious here? How do I associate the device change events to a specific device?

UPDATE: I still haven't come up with an ideal solution to this problem, but what I am doing is maintaining a list of currently connected devices (that I'm interested in) in memory, and every time an event is handled (see above), I query the Win32_PnPEntity to see if the devices I have stored in my connected device list are still connected. This is a sub-optimal solution, because it just seems weird that I can't get any specific device identification information from the event that indicates "device change event". Seems VERY strange, that this info is unavailable. sigh

like image 463
warriorpostman Avatar asked Mar 11 '11 22:03

warriorpostman


1 Answers

Okay, so after some further investigation and experimenting, I've discovered that I need to use a different WMI query in order to solve my problem, which is to associate a device change event with a specific device. In this case, I need to find what seems to be conventionally referred to in WMI as "TargetInstance".

So, I used the following WMI query code instead

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

So the difference here is, that the __InstanceCreationEvent has a property called "TargetInstance", which is EXACTLY what I was looking for. I cast the TargetInstance property to a ManagementBaseObject (which is of type "Win32_PnPEntity" (per the ISA clause in the query above), and Voila! I get the specific device that was created.

It still sort of baffles me as to how my original query "Select * from Win32_DeviceChangeEvent" would be useful to anyone at all, since there's no additional information provided after a generic event notification is fired. Either way, this new query a significantly cleaner solution to the my problem. WMI seems pretty powerful, but finding the correct query to use can be tricky, and requires some experimenting.

like image 132
warriorpostman Avatar answered Sep 20 '22 14:09

warriorpostman