You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:43:23