在MAUI的Windows平台中,如何捕获USB设备断开连接事件?
在MAUI Windows平台检测USB设备断开
方法一:使用Windows.Devices.Enumeration API(推荐)
这个Windows Runtime原生API更贴合MAUI的WinUI 3环境,无需直接处理Win32消息,实现更简洁。
实现步骤
- 用
#if WINDOWS条件编译隔离Windows平台代码,避免影响其他平台。 - 初始化
DeviceWatcher并过滤USB设备,监听设备移除事件(对应USB断开)。
代码示例
#if WINDOWS using Windows.Devices.Enumeration; #endif public partial class MainPage : ContentPage { #if WINDOWS private DeviceWatcher _usbDeviceWatcher; #endif public MainPage() { InitializeComponent(); #if WINDOWS InitializeUsbDeviceWatcher(); #endif } #if WINDOWS private void InitializeUsbDeviceWatcher() { // 过滤USB接口设备的查询字符串 string usbDeviceSelector = DeviceInformation.CreateDeviceSelector("System.Devices.InterfaceClassGuid:=\"{86e0d1e0-8089-11d0-9ce4-08003e301f73}\""); _usbDeviceWatcher = DeviceInformation.CreateWatcher(usbDeviceSelector); // 监听USB设备断开事件 _usbDeviceWatcher.Removed += UsbDeviceRemoved; // 可选:监听USB设备连接事件 _usbDeviceWatcher.Added += UsbDeviceAdded; // 启动监听 _usbDeviceWatcher.Start(); } private void UsbDeviceRemoved(DeviceWatcher sender, DeviceInformationUpdate args) { // 回到主线程更新UI Dispatcher.Dispatch(() => { DisplayAlert("提示", $"USB设备已断开: {args.Id}", "确定"); }); } private void UsbDeviceAdded(DeviceWatcher sender, DeviceInformation args) { Dispatcher.Dispatch(() => { DisplayAlert("提示", $"USB设备已连接: {args.Name}", "确定"); }); } protected override void OnDisappearing() { base.OnDisappearing(); #if WINDOWS // 页面销毁时释放监听资源 if (_usbDeviceWatcher != null) { _usbDeviceWatcher.Removed -= UsbDeviceRemoved; _usbDeviceWatcher.Added -= UsbDeviceAdded; _usbDeviceWatcher.Stop(); _usbDeviceWatcher = null; } #endif } #endif }
方法二:模拟WndProc处理WM_DEVICECHANGE消息
如果习惯WinForms的WndProc模式,可以通过获取MAUI窗口句柄,注册设备通知后拦截WM_DEVICECHANGE消息。
实现步骤
- 获取MAUI Windows窗口的HWND句柄。
- 用P/Invoke调用
RegisterDeviceNotification注册USB设备通知。 - 替换窗口消息处理过程,捕获
WM_DEVICECHANGE并判断设备断开事件。
代码示例
#if WINDOWS using System.Runtime.InteropServices; using Microsoft.UI.Xaml; using WinRT.Interop; #endif public partial class MainPage : ContentPage { #if WINDOWS private IntPtr _windowHandle; private IntPtr _deviceNotificationHandle; private IntPtr _originalWndProc; // Win32 API声明 [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr RegisterDeviceNotification(IntPtr hWnd, IntPtr NotificationFilter, uint Flags); [DllImport("user32.dll", SetLastError = true)] private static extern bool UnregisterDeviceNotification(IntPtr hHandle); [DllImport("user32.dll")] private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, WndProcDelegate newProc); [DllImport("user32.dll")] private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); private delegate IntPtr WndProcDelegate(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); private const int GWL_WNDPROC = -4; private const uint DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000; private const int WM_DEVICECHANGE = 0x0219; private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; #endif public MainPage() { InitializeComponent(); #if WINDOWS // 获取MAUI窗口句柄 var window = Application.Current.Windows.First().Handler.PlatformView as Window; _windowHandle = WindowNative.GetWindowHandle(window); // 注册USB设备通知 RegisterUsbDeviceNotification(); // 替换窗口消息处理过程 _originalWndProc = SetWindowLongPtr(_windowHandle, GWL_WNDPROC, WndProc); #endif } #if WINDOWS private void RegisterUsbDeviceNotification() { var filter = new DEV_BROADCAST_DEVICEINTERFACE { dbcc_size = Marshal.SizeOf<DEV_BROADCAST_DEVICEINTERFACE>(), dbcc_devicetype = 0x00000005, // DBT_DEVTYP_DEVICEINTERFACE dbcc_classguid = new Guid("86e0d1e0-8089-11d0-9ce4-08003e301f73") // USB设备类GUID }; IntPtr filterPtr = Marshal.AllocHGlobal(Marshal.SizeOf<DEV_BROADCAST_DEVICEINTERFACE>()); Marshal.StructureToPtr(filter, filterPtr, false); _deviceNotificationHandle = RegisterDeviceNotification(_windowHandle, filterPtr, DEVICE_NOTIFY_WINDOW_HANDLE); Marshal.FreeHGlobal(filterPtr); } private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam) { if (msg == WM_DEVICECHANGE && wParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE) { // 处理USB断开逻辑 Dispatcher.Dispatch(() => { DisplayAlert("提示", "USB设备已断开", "确定"); }); } // 调用原始窗口过程 return CallWindowProc(_originalWndProc, hWnd, msg, wParam, lParam); } protected override void OnDisappearing() { base.OnDisappearing(); #if WINDOWS // 释放资源 if (_deviceNotificationHandle != IntPtr.Zero) { UnregisterDeviceNotification(_deviceNotificationHandle); } if (_originalWndProc != IntPtr.Zero) { SetWindowLongPtr(_windowHandle, GWL_WNDPROC, Marshal.GetDelegateForFunctionPointer<WndProcDelegate>(_originalWndProc)); } #endif } [StructLayout(LayoutKind.Sequential)] private struct DEV_BROADCAST_DEVICEINTERFACE { public int dbcc_size; public int dbcc_devicetype; public int dbcc_reserved; public Guid dbcc_classguid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] public string dbcc_name; } #endif }
注意事项
- 方法一的
DeviceWatcher无需处理复杂Win32逻辑,更适合MAUI项目。 - 所有Windows平台代码必须用
#if WINDOWS包裹,避免编译错误。 - 更新UI时必须通过
Dispatcher.Dispatch回到主线程,保证线程安全。
内容的提问来源于stack exchange,提问作者mariano desivo
相关产品推荐
相关产品推荐

