Friday, February 29, 2008

USB Port Insert / Remove detection using WMI

We can use the Windows Management Instrumentation (WMI) which is a component of the Windows operating system that allows you to programmatically access management information in an enterprise environment.

First we should add the System.Management name space as a reference to our project

The add: using System.Management;

When a USB device is inserted a 'Win32_USBControllerdevice' record is added to the operating system's metabase and when the device is removed, that record will be deleted.

So we have to add two events to the same record and these events are "__InstanceCreationEvent" for insertion and "__InstanceDeletionEvent" for removal.

The following method "StartMonitoringPort()" adds an event handler that is fired when a USB device is inserted.

ManagementEventWatcher omewStartEventWatcher;
private void StartMonitoringPort()
{
WqlEventQuery q;
ManagementOperationObserver observer = new
ManagementOperationObserver();

// Bind to local machine
ManagementScope scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true; //sets required privilege

try
{
q = new WqlEventQuery();
q.EventClassName = "__InstanceCreationEvent";
q.WithinInterval = new TimeSpan(0,0,3);
q.Condition = @"TargetInstance ISA 'Win32_USBControllerDevice'";
omewStartEventWatcher = new ManagementEventWatcher(scope, q);
omewStartEventWatcher.EventArrived += new EventArrivedEventHandler(UsbEventArrived);
omewStartEventWatcher.Start();
}
catch(Exception ex)
{
if (omewStartEventWatcher != null)
omewStartEventWatcher.Stop();
throw ex;
}
finally
{
}
}

private void StopMonitoringPort()
{
if (omewStartEventWatcher != null)
omewStartEventWatcher.Stop();
}

public void UsbEventArrived(object sender, EventArrivedEventArgs e)
{
//Get the Event object and display it
foreach(PropertyData pd in e.NewEvent.Properties)
{
ManagementBaseObject mbo = null;
if(( mbo = pd.Value as ManagementBaseObject) != null)
{
SetText("USB device is inserted at " + DateTime.Now.ToString() + "\r\n");
foreach(PropertyData prop in mbo.Properties)
// lblStatus.Text = InputData;
// because of different threads this
// does not work properly !!
if (prop.Name == "Antecedent" || prop.Name == "Dependent" )
SetText(string.Format("{0}\r\n{1}\r\n{2}\r\n{3}\r\n", prop.Name, prop.Value, prop.IsArray,prop.IsLocal));
}
}
}

delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.txtLead.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else this.txtLead.Text += text;
}

Important note: you should stop the watcher before exiting the application or else an excption is thrown

Now to add another handler for that fire when the USB device is removed all you have to do is just to set the EventClassName property of the WqlEventQuery object to “__InstanceDeletionEvent”.