Listen for Removable Device events


Handling device events in the .net framework is not an easy task and is really cumbersome for many developers. Application developers often need to listen for some hardware events, such as adding or removing a USB Flash memory or disconnecting an external hard disk and do some application logic based on that event. For example, consider an application that runs on a server and the administrator wants to keep track of what Plug & Play devices are being attached to this server on daily basis. We also want to track the name of the attached device, its size and probably the files that are being transfered from and to the device.

It seems frustrating and hard to implement using the ordinary .net libraries available. So we will resort to using WMI to query the operating system for this information and create or own RemovableDevice wrapper.

We need to add a reference to System.Management to get the WMI APIs. The key behind this whole feature lies in the ManagementEventWatcher class by firing a query against Win32_VolumeChangeEvent, which is a win32 object that stores information about volumes and storage devices attached to the machine, to listen for Hardware events, then handle the MediaConnectWatcher.EventArrived event to distinguish the event types and fire our custom events based on those. Below is the full implementation of our RemovableDevice wrapper:


Imports System.Management

Public Class RemovableDevice

    Public Enum VolumeEventType As UInteger
        ConfigurationChange = 1
        DeviceArrival = 2
        DeviceRemoval = 3
        Docking = 4
        Any = 5
    End Enum

    Private Shared WithEvents MediaConnectWatcher As System.Management.ManagementEventWatcher
    Public Shared Event OnAnyChange(ByVal EventType As VolumeEventType, ByVal DriveName As String, ByVal TimeCreated As Date)
    Public Shared Event OnConfigurationChange(ByVal DriveName As String, ByVal TimeCreated As Date)
    Public Shared Event OnArrival(ByVal DriveName As String, ByVal TimeCreated As Date)
    Public Shared Event OnRemoval(ByVal DriveName As String, ByVal TimeCreated As Date)
    Public Shared Event OnDock(ByVal DriveName As String, ByVal TimeCreated As Date)
    Private Shared mEventType As VolumeEventType

    Public Shared Sub ListenForChanges(Optional ByVal EventType As VolumeEventType = VolumeEventType.Any)
        mEventType = EventType
        Dim query2 As String
        If EventType = 5 Then
            query2 = "SELECT * FROM Win32_VolumeChangeEvent"
        Else
            query2 = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType=" & EventType
        End If
        ' Dim query2 As String = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA ""Win32_USBHub"""
        MediaConnectWatcher = New System.Management.ManagementEventWatcher(query2)
        MediaConnectWatcher.Start()
    End Sub

    Private Shared Sub Arrived(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs) Handles MediaConnectWatcher.EventArrived
        Dim timeCreated As Date = Date.FromBinary(e.NewEvent("Time_Created"))
        Select Case e.NewEvent("EventType")
            Case 1
                RaiseEvent OnConfigurationChange(e.NewEvent("DriveName"), timeCreated)
            Case 2
                RaiseEvent OnArrival(e.NewEvent("DriveName"), timeCreated)
            Case 3
                RaiseEvent OnRemoval(e.NewEvent("DriveName"), timeCreated)
            Case 4
                RaiseEvent OnDock(e.NewEvent("DriveName"), timeCreated)
        End Select
        If mEventType = VolumeEventType.Any Then
            RaiseEvent OnAnyChange(e.NewEvent("EventType"), e.NewEvent("DriveName"), timeCreated)
        End If
    End Sub
End Class

The code below calls into ListenForChanges shared method to listen for any of the 5 standard volume events in windows but each event is handled separatly:

        Dim device As New RemovableDevice
        RemovableDevice.ListenForChanges(VolumeEventType.Any)
    Private Sub Device_OnAnyChange(ByVal EventType As VolumeEventType, ByVal DriveName As String, ByVal TimeCreated As Date) Handles d.OnAnyChange
        MsgBox(EventType & DriveName & TimeCreated)
    End Sub

    Private Sub Device_OnArrival(ByVal DriveName As String, ByVal TimeCreated As Date) Handles d.OnArrival
        MsgBox("i am arrived")
    End Sub

    Private Sub Device_OnRemoval(ByVal DriveName As String, ByVal TimeCreated As Date) Handles d.OnRemoval
        MsgBox("i am removed")
    End Sub

    Private Sub Device_OnDock(ByVal DriveName As String, ByVal TimeCreated As Date) Handles d.OnDock
        MsgBox("i am docked")
    End Sub

    Private Sub Device_OnConfigurationChange(ByVal DriveName As String, ByVal TimeCreated As Date) Handles d.OnConfigurationChange
        MsgBox("my config is changed")
    End Sub

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: