Мониторинг USB-накопителей и извлечение информации об устройстве с помощью DeviceWatcher?

Я разработчик WinForms, и я уже знал, как контролировать USB, который подключается или отключается с помощью WMI, но время назад я обнаружил DeviceWatcher класс для современных приложений Windows, этот класс впервые заинтересовался, потому что кажется очень улучшенной и эффективной альтернативой для замены всех этих "старых" кодов WMI, которые объясняют, как контролировать диски до Интернета, но до вчерашнего дня (спасибо этот пост). Я не знаю, как использовать DeviceWatcher в проекте WinForms, но теперь я использую DeviceWatcher в проекте WinForms.

Проблема в том, что, возможно, я ошибаюсь, но я думаю, что это не то, чего я ожидал, просто я не могу найти какую-либо документацию об DeviceWatcher (только пример MSDN выше), и я не могу найти способ получить необходимую информацию для мониторинга событий накопителя, я попытался обработать все события DeviceWatcher, чтобы распечатать в консоли Debug все данные, содержащиеся в аргументах, с надеждой найти что-то, что могло бы мне помочь... но нет, я очень зациклен на использовании класса DeviceWatcher, и я не могу представить, как это сделать.

Когда я подключаю или отсоединяю USB, я просто вижу две вещи: идентификатор оборудования и свойство InterfaceEnabled (что я не знаю, определяет ли это наличие устройства), ничего интересного больше.

Что я сделал:

· Получить идентификаторы аппаратного устройства.

Что я хотел бы сделать:

. Извлеките тип устройства (в отличие от USB и других устройств), когда устройство подключено, отключено и отключено.

· Получить доступность устройства (я имею в виду, доступно ли устройство для чтения/записи данных), когда устройство подключено, отключено и отключено.

. Извлечь букву устройства, когда устройство подключено, отсоединение и отсоединение.

· Получить описание метки устройства, когда устройство подключено, отключено и отключено.

Код:

Public Class DeviceWatcher_Test

    Private WithEvents dw As DeviceWatcher = DeviceInformation.CreateWatcher

    ' It suposed that these properties should exist in the "e.properties" on the "dw_updated" event?, not in my case.
    ' Dim props As String() = {"System.ItemNameDisplay", "System.Devices.ModelName", "System.Devices.Connected"}

    Private Sub Test() Handles MyBase.Load

        dw.Start()

    End Sub

    Private Sub dw_Added(ByVal sender As DeviceWatcher, ByVal e As DeviceInformation) _
    Handles dw.Added

        Dim sb As New System.Text.StringBuilder

        With sb
            .AppendLine("dw_added")
            .AppendLine("********")
            .AppendLine(String.Format("Interface ID.: {0}", e.Id))
            .AppendLine(String.Format("Friendly Name: {0}", e.Name))
            .AppendLine(String.Format("Is Enabled?..: {0}", e.IsEnabled))
        End With

        Debug.WriteLine(sb.ToString)

    End Sub

    Private Sub dw_Removed(ByVal sender As DeviceWatcher, ByVal e As DeviceInformationUpdate) _
    Handles dw.Removed

        Dim sb As New System.Text.StringBuilder

        With sb
            .AppendLine("dw_Removed")
            .AppendLine("**********")
            .AppendLine(String.Format("Interface ID:{0}", e.Id))

            For Each item As KeyValuePair(Of String, Object) In e.Properties
                .AppendLine(String.Format("TKey:{0}, TVal:{1} (TVal Type:{2})",
                                          item.Key, item.Value.ToString, item.Value.GetType.Name))
            Next

        End With

        Debug.WriteLine(sb.ToString)

    End Sub

    Private Sub dw_Updated(ByVal sender As DeviceWatcher, ByVal e As DeviceInformationUpdate) _
    Handles dw.Updated

        Dim sb As New System.Text.StringBuilder

        With sb
            .AppendLine("dw_Updated")
            .AppendLine("**********")
            .AppendLine(String.Format("Interface ID: {0}", e.Id))

            For Each item As KeyValuePair(Of String, Object) In e.Properties

                If item.Key.EndsWith("InterfaceEnabled", StringComparison.OrdinalIgnoreCase) Then
                    Dim Result As Boolean = CBool(item.Value)
                    ' I'm not sure whether the 'Result' value really determines this:
                    .AppendLine(String.Format("The device is accessible?:{0}", CStr(Result)))

                Else
                    .AppendLine(String.Format("TKwy:{0}, TVal:{1} (TVal Type:{2})",
                                              item.Key, item.Value.ToString, item.Value.GetType.Name))

                End If

            Next

        End With

        Debug.WriteLine(sb.ToString)

    End Sub

    Private Sub dw_Stopped(ByVal sender As DeviceWatcher, ByVal e As Object) _
    Handles dw.Stopped

        Dim sb As New System.Text.StringBuilder

        With sb
            .AppendLine("dw_Stopped")
            .AppendLine("**********")
            .AppendLine(String.Format("e:{1} (e Type:{2})",
                                      e.ToString, e.GetType.Name))

        End With

        Debug.WriteLine(sb.ToString)

    End Sub

    Private Sub dw_EnumerationCompleted(ByVal sender As DeviceWatcher, ByVal e As Object) _
    Handles dw.EnumerationCompleted

        If e IsNot Nothing Then

            Dim sb As New System.Text.StringBuilder

            With sb
                .AppendLine("EnumerationCompleted")
                .AppendLine("********************")
                .AppendLine(String.Format("e:{1} (e Type:{2})",
                                          e.ToString, e.GetType.Name))

            End With

            Debug.WriteLine(sb.ToString)

        End If

    End Sub

End Class

Ответ 1

Это будет следить за приходом и удалением USB-накопителей и сообщать о DriveLetter, метке тома и серийном номере устройства. Для вашего удобства он поднимает 2 события:

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

Это касается только того, что новый диск добавлен/удален, он не будет обнаруживать такие вещи, как извлеченный или вставленный компакт-диск, или вставлять носитель в слот для считывания карт.

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

Как реализовать 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

Наблюдатель устройств работает в другом потоке, поэтому, если вы хотите опубликовать уведомление для элемента управления, вам придется использовать делегат:

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

Затем из события Device Added, например:

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 будет таким же, кроме "Удалено" в качестве третьего параметра в тексте сообщения.

USBWatcher также имеет метод StopWatching, чтобы отключить наблюдателя на время, и StartWatching, чтобы запустить и перезапустить его. Ваше приложение должно вызвать StopWatching, когда приложение закончится, чтобы предотвратить ошибки COM; просто добавьте watcher.StopWatching в событие закрытия формы.

Это делает то, что вы хотите - поднять события, когда вставлен съемный носитель, и вернуть информацию о них - просто не совсем так, как вы этого хотели. Он использует проверенную и проверенную WMI, а не метод Win8, который пока имеет только разреженный документ на MSDN и будет работать только на Win8.

Ответ 2

вы можете использовать WMI для обнаружения, если вставьте перо. Вы должны добавить ссылку на DLL System.Management инфраструктуры dotnet.

вы можете получить Devide Details как:

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

Ответ 3

Вы можете получить PnPObject из идентификатора интерфейса, который даст вам больше информации о конкретном устройстве.

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

кажется довольно интересным парнем. У вас есть несколько различных опций для определения для PnpObjectType,

DeviceInterface | deviceInterface - PnpObject представляет собой интерфейс устройства.

DeviceContainer | deviceContainer - PnpObject представляет контейнер устройства.

Устройство | device -PnpObject представляет собой устройство.

DeviceInterfaceClass | deviceInterfaceClass - PnpObject представляет класс интерфейса устройства.

Идентификатор - это идентификатор интерфейса, который вы уже получили.

Также обратите внимание, что у вас есть список свойств, которые вы можете запросить (аргумент requstedProperties): http://msdn.microsoft.com/en-us/library/hh464997.aspx#ListOfCanonicalProperties.

Это правда, что вам не слишком много, но не бойтесь. Их гораздо больше: http://msdn.microsoft.com/en-us/library/ff553416.aspx

Если вы проверите devpkey.h, вы можете найти интересные свойства, например:

  • DEVPKEY_Device_DevType
  • DEVPKEY_Storage_Removable_Media
  • DEVPKEY_Storage_Portable  -

Некоторые из вещей - устройство specfc, некоторые из них. Вы можете получить еще больше свойств с помощью devmgmt.msc (Details- > Property). Там также куча вещей в реестре. Модель свойств унифицированного устройства обсуждает это: http://msdn.microsoft.com/en-us/library/ff553515(v=vs.85).aspx

PnP api имеет следующие методы:

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, ...)

Вы можете прочитать эту статью: http://www.codeproject.com/Articles/458550/Device-enumeration-in-Windows

В нем есть все, исходный код, ключи и показано, как сбрасывать все свойства из устройств в файл. Таким образом вы можете узнать, какие свойства имеет ваш USB-накопитель.