La necessità è quella di intercettare il plug/unplug di un qualsiasi device USB. Il problema è che il sistema operativo sparapacchia la notifica nella massage pump e il subclassing in Wpf è concetto inesistente…
Quindi?
E’ un po’ contorto ma alla fine con una manciata di righe di codice ci si arriva:
Public Interface IHardwareMonitor
Event DeviceAttached As EventHandler
Event DeviceRemoved As EventHandler
End Interface
definiamo quello che vogliamo ottenere: un semplice observer.
The Trick
A questo punto lo possiamo implementare, ad esempio, in questo modo:
Public NotInheritable Class WpfHardwareMonitor
Implements IHardwareMonitor
Public Event DeviceAttached(ByVal sender As Object, ByVal e As System.EventArgs) Implements Plc.IHardwareMonitor.DeviceAttached
Private Sub OnDeviceAttached()
RaiseEvent DeviceAttached(Me, EventArgs.Empty)
End Sub
Public Event DeviceRemoved(ByVal sender As Object, ByVal e As System.EventArgs) Implements Plc.IHardwareMonitor.DeviceRemoved
Private Sub OnDeviceRemoved()
RaiseEvent DeviceRemoved(Me, EventArgs.Empty)
End Sub
Dim source As HwndSource
Public Sub New()
AddHandler Application.Current.Exit, AddressOf OnAppExit
AddHandler Application.Current.MainWindow.Loaded, AddressOf OnLoaded
End Sub
Sub OnAppExit(ByVal sender As Object, ByVal e As ExitEventArgs)
source.RemoveHook(New HwndSourceHook(AddressOf WndProc))
RemoveHandler Application.Current.Exit, AddressOf OnAppExit
End Sub
Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
source = HwndSource.FromHwnd(New WindowInteropHelper(Application.Current.MainWindow).Handle)
source.AddHook(New HwndSourceHook(AddressOf WndProc))
RemoveHandler Application.Current.MainWindow.Loaded, AddressOf OnLoaded
End Sub
Const WM_DEVICECHANGE As Integer = &H219
Const DBT_DEVICEARRIVAL As Integer = &H8000
Const DBT_DEVICEREMOVECOMPLETE As Integer = &H8004
Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
If msg = WM_DEVICECHANGE Then
If wParam.ToInt32() = DBT_DEVICEARRIVAL Then
Me.OnDeviceAttached()
ElseIf wParam.ToInt32() = DBT_DEVICEREMOVECOMPLETE Then
Me.OnDeviceRemoved()
End If
End If
End Function
End Class
Il giochetto di fondo è quello di risuscire a ricavare l’handle di una finestra, top level, che in Wpf non serve:
source = HwndSource.FromHwnd(New WindowInteropHelper(Application.Current.MainWindow).Handle)
source.AddHook(New HwndSourceHook(AddressOf WndProc))
Il resto è normale codice per la gestione dei messaggi.
ndr
E’ VB.Net :-), mamma mia che fatica! non so se è perchè lo uso veramente di rado ma lo trovo decisamente ostico, decisamente. E’ evidente che dal punto di vista delle potenzialità non c’è differenza ma alcune cose mi laciano molto perplesso, molto.
.m