Search code examples
c#.netwpfwmi

Cannot implement USB Detection in .NET Framework using WMI API


  • I am trying to implement the code from the following link: Detecting USB drive insertion and removal using windows service and c#
  • I think the issue I am having is that my main UI thread isn't being notified by the background thread when the device is inserted or removed. I verified this by not being able to update the content of a label in my user control.
  • I have included my source code below:
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    foreach (var property in instance.Properties)
    {
        MessageBox.Show(property.Name + " = " + property.Value); // Dialog box appears as expected. 
        StatusMessage.Content = $"{property.Name} = {property.Value}";
    }
    StatusMessage.Content = "Removable Drive detected!"; //label content should be updated here, and for some reason it is not.
    bool isDriveRemoved = FindRemovableDrive(); //get the drive info
    if (isDriveRemoved || Count > 0)
    {
        Count = 0;
    }
    else
    {
        Count++;
    }
}

private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    foreach (var property in instance.Properties)
    {
        MessageBox.Show(property.Name + " = " + property.Value); // Dialog box appears as expected, but label is not updated. 
    }
    StatusMessage.Content = $"{property.Name} = {property.Value}";
    FileMenu.Items.Clear(); // the file menu should be getting cleared here. 
}

private void backgroundWorker1_DoWork(object sender, RoutedEventArgs e)
{
    WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");

    ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
    insertWatcher.EventArrived += DeviceInsertedEvent;
    insertWatcher.Start();

    WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
    ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
    removeWatcher.EventArrived += DeviceRemovedEvent;
    removeWatcher.Start();

    // Do something while waiting for events
    //Thread.Sleep(10000);
}

-Any input/solutions would be greatly appreciated.

Thanks for your time,

Michael


Solution

  • Rather than regularly scanning devices you can use a WMI Events to be notified when there is a hardware change.

    Starting a listener for plug & play events:

    var wmiPath = new ManagementPath(@"root\cimv2");
    var scope = new ManagementScope(wmiPath);
    scope.Connect();
    var instanceQuery = new WqlEventQuery("__InstanceOperationEvent",
                                            new TimeSpan(0, 0, 1),
                                            "TargetInstance isa \"Win32_PnPEntity\"");
    wmiWatcher = new ManagementEventWatcher(scope, instanceQuery);
    wmiWatcher.EventArrived += OnInstanceEvent;
    wmiWatcher.Start();
    

    The event handler:

    private void OnInstanceEvent(object sender, EventArrivedEventArgs ea) {
      var eventType = (string)ea.NewEvent["__CLASS"];
      var targetWmiObj = ea.NewEvent["TargetInstance"] as ManagementBaseObject;
      var deviceId = (string)targetWmiObj["deviceId"];
    
     if (String.Equals("__InstanceCreationEvent", (string)ea.NewEvent["__CLASS"], StringComparison.Ordinal)) {
       if (/* Filter on the device id for what is interesting here*/) {
         // Handle relevant device arriving
        }
      }
    }
    

    There are other values of NewEvent["__CLASS"] for other event types (including device removal).

    PS. This is (partial) code from a WinForms app that monitored for a specialised device being plagged in and then downloaded/uploaded data from it. All the work was done in the thread pool: everything here should just work under WPF.