Monitor USB drives and retrieve device Info using a DeviceWatcher?

后端 未结 3 1636
我在风中等你
我在风中等你 2020-12-01 16:40

I\'m a WinForms developer and I already knew how to monitor the USB\'s that connects or disconnects using WMI, but time ago I\'d discovered the DeviceWatche

相关标签:
3条回答
  • 2020-12-01 17:25

    This will watch for the Arrival and Removal of USB drives, and report the DriveLetter, Volume Label and device serial number. It raises 2 Events for your convenience:

    Public Event DeviceAdded(sender As Object, e As USBWatcherEventArgs)
    Public Event DeviceRemoved(sender As Object, e As USBWatcherEventArgs)
    

    This only watches for a new drive added/removed, it will not detect things like a CD being ejected or inserted, or inserting media into a card reader slot.

    Imports System.Management
    
    Public Class USBWatcher
    
        ' alternate method to use one event with an extra
        ' event property to report the action
        'Public Enum WatcherActions
        '    DriveInserted = 1
        '    DriveRemoved = 2
        'End Enum
    
        ' USB device added/removed args
        Public Class USBWatcherEventArgs
            Inherits EventArgs
    
            'Public Property WatcherAction As WatcherActions
            Public Property DriveLetter As String
            Public Property VolumeName As String
            Public Property VolumeSerial As String
    
            Friend Sub New(drv As String, vol As String, ser As String)
                DriveLetter = drv
                VolumeName = vol
                VolumeSerial = ser
                'WatcherAction = act
            End Sub
    
        End Class
    
        Private WithEvents Watcher As ManagementEventWatcher
    
        Public Event DeviceAdded(sender As Object, e As USBWatcherEventArgs)
        Public Event DeviceRemoved(sender As Object, e As USBWatcherEventArgs)
    
        Private pnpCol As Dictionary(Of String, Management.ManagementObject)
    
        Public Sub New()
    
        End Sub
    
        Public Sub StartWatching()
    
            ' get USBs currently attached
            pnpCol = GetUSBDevices()
    
            Dim arriveQuery = New WqlEventQuery("Select * from Win32_DeviceChangeEvent")
            Watcher = New ManagementEventWatcher(arriveQuery)
    
            ' we are watching you
            Watcher.Start()
    
        End Sub
    
        Public Sub StopWatching()
            Watcher.Stop()
    
        End Sub
    
        Private Function GetUSBDevices() As Dictionary(Of String,
                            Management.ManagementObject)
    
            Dim col As New Dictionary(Of String, Management.ManagementObject)
    
            Dim moSearch As New Management.ManagementObjectSearcher("Select * from Win32_LogicalDisk")
            Dim moReturn As Management.ManagementObjectCollection = moSearch.Get
    
    
            For Each mo As Management.ManagementObject In moReturn
                'Console.WriteLine("====")
                'DebugProperties(mo)
    
                ' some USB external drives report as DriveType 3 (local disk), but are
                ' in fact removable.  So monitor all disk drives.
                If col.ContainsKey(mo("DeviceID").ToString) = False Then
                    col.Add(mo("DeviceID").ToString, mo)
                End If
    
            Next
    
            Return col
        End Function
    
        Private inEvent As Boolean = False
    
        Private Sub arrive_EventArrived(ByVal sender As Object, 
                        ByVal e As System.Management.EventArrivedEventArgs) _
                        Handles Watcher.EventArrived
    
            If inEvent Then Exit Sub
            inEvent = True
    
            Dim col As Dictionary(Of String, Management.ManagementObject) = GetUSBDevices()
    
            Select Case col.Count
                Case Is > pnpCol.Count
                    ' device arrived
                    ProcessArrival(col)
                Case Is < pnpCol.Count
                    ' device removed
                    ProcessRemoval(col)
                Case Is = pnpCol.Count
                    ' noise...this is a chatty rascal
            End Select
    
            inEvent = False
    
        End Sub
    
        Private Sub ProcessArrival(col As Dictionary(Of String,
                   Management.ManagementObject))
            For Each kvp As KeyValuePair(Of String, 
                     Management.ManagementObject) In col
                If pnpCol.ContainsKey(kvp.Key) = False Then
    
                    'Console.WriteLine("{0} {1} ", kvp.Key, kvp.Value)
                    'DebugProperties(kvp.Value)
    
                    Dim ea As New USBWatcherEventArgs(kvp.Value("DeviceID").ToString,
                                          SafeString(kvp.Value("VolumeName")),
                                          SafeString(kvp.Value("VolumeSerialNumber")))
    
                    RaiseEvent DeviceAdded(Me, ea)
    
                    'rebuild baseline for next event
                    pnpCol = col
    
                End If
            Next
    
        End Sub
    
        Private Sub ProcessRemoval(col As Dictionary(Of String,
                        Management.ManagementObject))
            For Each kvp As KeyValuePair(Of String, 
                              Management.ManagementObject) In pnpCol
                If col.ContainsKey(kvp.Key) = False Then
    
                    'Console.WriteLine("{0} {1} ", kvp.Key, kvp.Value)
                    'DebugProperties(kvp.Value)
    
                    Dim ea As New USBWatcherEventArgs(kvp.Value("DeviceID").ToString,
                                          SafeString(kvp.Value("VolumeName")),
                                          SafeString(kvp.Value("VolumeSerialNumber")))
    
                    RaiseEvent DeviceRemoved(Me, ea)
    
                    'rebuild baseline for next event
                    pnpCol = col
    
                End If
            Next
    
        End Sub
    
        ' lots of things can be NOTHING depending on the manufacturer's
        ' attention to detail.  try to avoid NRE
        Private Function SafeString(obj As Object) As String
    
            If obj.GetType Is GetType(String) Then
                Return CType(obj, String)
            Else
                If obj IsNot Nothing Then
                    Return obj.ToString
                Else
                    Return "???"
                End If
            End If
    
        End Function
    
        ' debug tool to poll a management object to get the properties and values
        Private Sub DebugProperties(mo As Management.ManagementObject)
    
            For Each pd As PropertyData In mo.Properties
                If pd.Value IsNot Nothing Then
                    Console.WriteLine("{0} {1}", pd.Name,
                                      If(pd.Value IsNot Nothing,
                                         pd.Value.ToString,
                                         "Nothing"))
                End If
    
            Next
        End Sub
    
    End Class
    

    How to Implement USBWatcher

    ' local variable to catch events
    Private WithEvents watcher As USBWatcher
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        watcher = New USBWatcher
        watcher.StartWatching()     ' or add to a button click
        ' I DONT have it starting automatically when you create the watcher
    
    End Sub
    

    The Device Watcher runs on a different thread so if you want to post a notice to a control, you will have to use a delegate:

    Delegate Sub AddListItem(text As String)
    Private myDelegate As AddListItem = New AddListItem(AddressOf AddNewListItem)
    
    Private Sub AddNewListItem(text As String)
        myListBox.Items.Add(text)
    End Sub
    

    Then from the Device Added event, for example:

    Private Sub watcher_DeviceAdded(sender As Object, 
                e As USBWatcher.USBWatcherEventArgs) Handles watcher.DeviceAdded
    
        Console.Beep()
    
        Dim msg As String = String.Format("Drive {0} ({1})   {2}", 
                                           e.DriveLetter,
                                           e.VolumeName, "Inserted")
        If myListBox.InvokeRequired Then
            myListBox.Invoke(myDelegate, New Object() {msg})
        Else
            myListBox.Items.Add(msg)
        End If
    
    End Sub
    

    DeviceRemoved would be the same except "Removed" as the third param in the message text.

    USBWatcher also has a StopWatching method to turn off the watcher for a time, and StartWatching to start and restart it. Your app should call StopWatching when the app ends to prevent COM errors; just add watcher.StopWatching in the form close event.

    This does what you want - raise events when removable media is inserted and return the information about them - just not exactly how you wanted it. It uses tried and tested WMI rather than the Win8 method, which is as yet has only sparse documention on MSDN and would only work on Win8.

    0 讨论(0)
  • 2020-12-01 17:26

    you can use WMI to detect, if pen drive is inserted. You have to add reference to the System.Management dll of dotnet framework.

    you can get Devide Details as :

    Public Function SerialNO(ByVal DriveNameWithColon As String) As String
        Dim disk As ManagementObject = New ManagementObject("win32_logicaldisk.deviceid='" + DriveNameWithColon + "'")
        disk.Get()
        Return disk("VolumeSerialNumber").ToString()
    End Function
    
    0 讨论(0)
  • 2020-12-01 17:44

    You can get PnPObject from the interface ID which will give you more device specific information.

    public static IAsyncOperation<PnpObject> CreateFromIdAsync(
      PnpObjectType type, 
      string id, 
      IEnumerable<string> requestedProperties
    )
    

    seems pretty interesting fellah. You have few different options to specfy for PnpObjectType,

    DeviceInterface | deviceInterface - The PnpObject represents a device interface.

    DeviceContainer | deviceContainer - The PnpObject represents a device container.

    Device | device -The PnpObject represents a device.

    DeviceInterfaceClass | deviceInterfaceClass - The PnpObject represents a device interface class.

    The id actually is interface id, which you already received.

    Also note that you have list of properties you can ask for(requstedProperties argument): http://msdn.microsoft.com/en-us/library/hh464997.aspx#ListOfCanonicalProperties.

    It's true that there's not too much for you, but don't be scared. There's a lot more of them: http://msdn.microsoft.com/en-us/library/ff553416.aspx

    If you check devpkey.h, you can find interesting properties, such as:

    • DEVPKEY_Device_DevType
    • DEVPKEY_Storage_Removable_Media
    • DEVPKEY_Storage_Portable
    • -

    Some of the things are device specfc, some of not. You can get even more properties through devmgmt.msc(Details->Property). There's also bunch of stuff in the registry. The Unified device property model discusses this: http://msdn.microsoft.com/en-us/library/ff553515(v=vs.85).aspx

    PnP api has following methods:

    Await DeviceInformation.FindAllAsync()
    Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceContainer, ...)
    Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.Device, ...)
    Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterface, ...) 
    Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterfaceClass, ...)  
    Await Pnp.PnpObject.CreateFromIdAsync(..., id, ...)
    

    You can read this article: http://www.codeproject.com/Articles/458550/Device-enumeration-in-Windows

    It has everything, source code, keys, and shows how to dump all the properties from devices into file. This way you can see what properties your USB stick has.

    0 讨论(0)
提交回复
热议问题