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

Windows系统下C#如何检测USB设备触发USB Selective Suspend休眠事件

USB选择性挂起事件检测解决方案

1. 原生Windows消息实现

你现有代码仅处理了设备插拔相关的WM_DEVICECHANGE事件子集,要捕获USB挂起/唤醒事件,需要新增两类消息的处理:

  • 全局系统挂起/唤醒事件:通过WM_POWERBROADCAST消息(值为0x0218)捕获,对应WParam参数:
    • PBT_APMSUSPEND(值0x0004):系统即将进入挂起状态,所有USB设备会被同步挂起
    • PBT_APMRESUMEAUTOMATIC(值0x0012):系统从挂起状态恢复
  • 单个USB设备的选择性挂起/唤醒事件:在现有WM_DEVICECHANGE逻辑中新增DBT_POWERSTATECHANGE事件(WParam值为0x8019)的处理,该事件会携带对应设备的路径信息,和你要监控的条码扫描器的设备实例路径匹配后,即可精准判断目标设备的电源状态变化。

修改后的参考代码如下:

// 提前定义所需常量
private const int WM_POWERBROADCAST = 0x0218;
private const int PBT_APMSUSPEND = 0x0004;
private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
private const int DBT_POWERSTATECHANGE = 0x8019;

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_DEVICECHANGE:    // (0x0219)
            Console.WriteLine("Device state changed");
            switch (m.WParam.ToInt32()) 
            {
                case Win32Usb.DEVICE_ARRIVAL:   // 设备插入
                    Console.WriteLine("Device Inserted");
                    break;
                case Win32Usb.DEVICE_REMOVECOMPLETE:    // 设备移除
                    Console.WriteLine("Device Removed");
                    break;
                case DBT_POWERSTATECHANGE: // 设备电源状态变更
                    // 解析LParam指向的DEV_BROADCAST_DEVICEINTERFACE结构,匹配目标设备路径即可判断是否为目标扫描器的挂起/唤醒事件
                    Console.WriteLine("Target device power state changed");
                    break;
            }                    
            break;   
        case WM_POWERBROADCAST:
            switch (m.WParam.ToInt32())
            {
                case PBT_APMSUSPEND:
                    Console.WriteLine("System will suspend, USB devices will be suspended");
                    break;
                case PBT_APMRESUMEAUTOMATIC:
                    Console.WriteLine("System resumed from suspend");
                    break;
            }
            break;
    }
    base.WndProc(ref m);
}

2. 第三方库实现方案

目前主流的.NET USB类库没有直接封装选择性挂起事件的检测接口,可通过以下成熟库扩展实现:

  • LibUsbDotNet:.NET生态最常用的USB操作库,支持直接读取目标设备的电源状态寄存器,可通过低优先级后台线程每300-500ms轮询一次设备的CONFIG_PM_RUNTIME状态,即可判断设备是否进入选择性挂起状态,轮询开销极低不会影响主程序性能。
  • HidLibrary:绝大多数USB条码扫描器属于免驱动的HID类设备,可使用该库直接获取设备电源状态,订阅库提供的设备属性变更事件,过滤出电源状态变更通知即可实现检测。

补充优化方案

如果业务允许,更建议直接主动阻止目标设备触发选择性挂起:打开设备句柄后调用DeviceIoControlAPI发送IOCTL_USB_SET_SELECTIVE_SUSPEND控制码,单独为该设备禁用选择性挂起,不需要修改全局系统电源设置,该方案比检测挂起后再处理的稳定性更高。

内容的提问来源于stack exchange,提问作者Jeremy Deters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 17:54:01