Мониторинг USB-накопителей и получение информации об устройстве с помощью DeviceWatcher?
Я приложения WinForms разработчик и я уже знали, как контролировать USB, который подключается или отключается с помощью WMI, но некоторое время назад я обнаружил DeviceWatcher класс для современных приложений Windows, Этот класс заинтересовал в первый раз, потому что кажется очень улучшенной и эффективной альтернативой для замены всех этих "старых" кодов WMI, которые объясняют, как контролировать диски через Интернет, но до вчерашнего дня (благодаря этот пост) Я понятия не имею о как использовать DeviceWatcher в проекте WinForms, но теперь я использую DeviceWatcher в проекте WinForms.
проблема в том, что, возможно, я ошибаюсь, но я думаю, что это не совсем то, что я ожидал, просто я не могу найти никакой документации о DeviceWatcher (только пример MSDN выше), и я не могу найти способ получить необходимую информацию для мониторинга событий диска, я попытался обработать все события DeviceWatcher для печати в консоли отладки все данные, содержащиеся в аргументах, с надеждой найти что-то, что может мне помочь ...но нет, я очень застрял с использованием DeviceWatcher класс, и я не могу себе представить, как procceed.
когда я подключаю или отключаю USB, я вижу две вещи: идентификатор оборудования и свойство "InterfaceEnabled" (которое я не знаю, определяет ли это доступность устройства), ничего интересного больше.
что у меня есть выполнено:
* получить идентификатор аппаратного устройства.
что я хотел бы сделать:
* извлеките тип устройства (для разницы между USB и другими устройствами), когда устройство подключено, отключено и отключено.
* получить доступность устройства (я имею в виду, доступно ли устройство для чтения/записи данных на нем) , когда устройство подключено, отключается и разъединенный.
* извлеките букву устройства, когда устройство подключено, отключено и отключено.
* получить метку устройства-Описание, Когда устройство подключено, отключено и отключено.
код:
Public Class DeviceWatcher_Test
Private WithEvents dw As DeviceWatcher = DeviceInformation.CreateWatcher
' It's 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
3 ответов
это будет следить за прибытием и удалением 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
затем с устройства добавлено событие, например:
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.
вы можете использовать WMI для обнаружения, если вставлен pen drive. Вы должны добавить ссылку на System.Dll управления dotnet framework.
вы можете получить детали Devide как:
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
Вы можете получить 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