Чтобы получить доступ к событиям USB, нам нужно несколько вещей.
Сначала нам нужно обратиться к некоторым методам в user32.dll.
namespace Example
{
// https://www.pinvoke.net/default.aspx/Structures.DEV_BROADCAST_DEVICEINTERFACE
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_DEVICE_INTERFACE
{
public int Size;
public int DeviceType;
public int Reserved;
public Guid ClassGuid;
public short Name;
}
public class Win32Native
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr RegisterDeviceNotification(
IntPtr hRecipient,
IntPtr notificationFilter,
uint flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
}
}
Нам нужно это, чтобы иметь возможность зарегистрировать нашОкно WPF для прослушивания событий USB.
namespace Example
{
public class UsbEventRegistration : IDisposable
{
private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
private static readonly s_guidDevInterfaceUsbDevice =
new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
private readonly IntPtr _windowHandle;
private IntPtr _notificationHandle = IntPtr.Zero;
public bool IsRegistered => _notificationHandle != IntPtr.Zero;
public UsbEventRegistration(IntPtr windowHandle)
{
_windowHandle = windowHandle;
}
public void Register()
{
var dbdi = new DEV_BROADCAST_DEVICE_INTERFACE
{
DeviceType = DBT_DEVTYP_DEVICEINTERFACE,
Reserved = 0,
ClassGuid = s_guidDevInterfaceUsbDevice,
Name = 0,
};
dbdi.Size = Marshal.SizeOf(dbdi);
IntPtr buffer = Marshal.AllocHGlobal(dbdi.Size);
Marshal.StructureToPtr(dbdi, buffer, true);
_notificationHandle = Win32Native.RegisterDeviceNotification(
_windowHandle,
buffer,
0);
}
// Call on window unload.
public void Dispose()
{
Win32Native.UnregisterDeviceNotification(_notificationHandle);
}
}
}
Наконец, подготовьте свой код позади окна WPF.
namespace Example
{
public partial class WPFWindow : Window
{
private UsbEventRegistration _usbEventRegistration;
public WPFWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// IMO this should be abstracted away from the code-behind.
var windowSource = (HwndSource)PresentationSource.FromVisual(this);
_usbEventRegistration = new UsbEventRegistration(windowSource.Handle);
// This will allow your window to receive USB events.
_usbEventRegistration.Register();
// This hook is what we were aiming for. All Windows events are listened to here. We can inject our own listeners.
windowSource.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Here's where the help ends. Do what you need here.
// Get additional info from http://www.pinvoke.net/
// USB event message is msg == 0x0219 (WM_DEVICECHANGE).
// USB event plugin is wParam == 0x8000 (DBT_DEVICEARRIVAL).
// USB event unplug is wParam == 0x8004 (DBT_DEVICEREMOVECOMPLETE).
// Your device info is in lParam. Filter that.
// You need to convert wParam/lParam to Int32 using Marshal.
return IntPtr.Zero;
}
}
}