setupapi是windows下枚举usb设备的首选方案,通过setupdigetclassdevs配合guid_devinterface_usb_device获取设备信息集,再调用setupdienumdeviceinterfaces和setupdigetdeviceinterfacedetail获取devicepath等关键信息。

Windows上用SetupAPI枚举USB设备最直接
在Windows下,SetupAPI 是读取USB设备信息的首选——它不依赖第三方库,能拿到厂商ID、产品ID、设备描述、实例路径等完整系统级信息,且权限要求比驱动层低得多。
关键函数是 SetupDiGetClassDevs 配合 GUID_DEVCLASS_USB 或更精确的 GUID_DEVINTERFACE_USB_DEVICE。用后者能绕过“类驱动设备”干扰,只抓真实USB接口设备。
- 必须先调用
SetupDiGetClassDevs获取设备信息集,传入DIGCF_PRESENT | DIGCF_DEVICEINTERFACE - 循环调用
SetupDiEnumDeviceInterfaces枚举每个接口,再用SetupDiGetDeviceInterfaceDetail拿到DevicePath(这是后续打开设备或查属性的基础) - 设备描述、硬件ID等需额外调用
SetupDiGetDeviceRegistryProperty,传入SPDRP_FRIENDLYNAME或SPDRP_HARDWAREID - 别漏掉
SetupDiDestroyDeviceInfoList,否则句柄泄漏,多次调用后会失败
libusb_get_device_list返回空?检查初始化和权限
libusb_get_device_list 返回 NULL 很常见,但原因集中:不是代码写错,而是环境没配好。
Windows下默认无法访问USB设备描述符,libusb需要WinUSB或libusb-win32驱动绑定;Linux下则要udev规则或sudo;macOS相对简单但需确认是否被Gatekeeper拦截。
立即学习“C++免费学习笔记(深入)”;
- Windows:用
Zadig工具把目标设备替换成WinUSB驱动,或确保设备已由 libusb 官方inf安装成功 - Linux:运行
lsusb确认设备在线,再检查/etc/udev/rules.d/99-libusb.rules是否存在并包含SUBSYSTEM=="usb", MODE="0664", GROUP="plugdev" - 调用前必须
libusb_init(NULL),返回非0值说明初始化失败,常见于DLL未找到或ABI不匹配 -
libusb_get_device_list返回的是指针数组,长度由第二个参数传出,别直接sizeof数组
获取USB设备序列号为什么总是失败?
序列号(iSerialNumber)不是所有设备都提供,也不是所有系统都能读——即使设备支持,Windows默认策略也常屏蔽它以防指纹追踪。
SetupAPI里,SPDRP_SERIALNUMBER 属性在多数情况下返回空字符串;libusb中 libusb_get_string_descriptor_ascii 读取描述符时若返回 LIBUSB_ERROR_NOT_FOUND 或 LIBUSB_ERROR_ACCESS,基本可判定硬件未暴露或系统限制。
- Windows:需以管理员权限运行,且设备必须处于活动状态(不能是休眠或断开重连瞬间)
- libusb:先用
libusb_open打开设备,再调用libusb_get_string_descriptor_ascii,传入device->device_descriptor.iSerialNumber;未 open 就读会返回 -1 - 某些USB转串口芯片(如CH340、CP210x)根本没实现串号描述符,此时只能靠
HardwareID+ 端口号组合做唯一标识
跨平台统一获取 VendorID/ProductID 的最小可行方案
想一行代码在 Windows/Linux/macOS 都拿到 idVendor 和 idProduct?别绕弯,就用 libusb —— 它的 libusb_device_descriptor 结构体字段是标准且稳定的。
注意:libusb 设备列表里的设备对象(libusb_device *)本身不包含描述符,必须调用 libusb_get_device_descriptor 显式获取,否则字段全是零。
- 不要在
libusb_get_device_list后直接访问device->descriptor.idVendor,那是野指针 - Linux 下如果只想要 VID/PID 不操作设备,无需
libusb_open,libusb_get_device_descriptor足够 - macOS 上部分设备可能因签名问题拒绝 descriptor 读取,此时 fallback 到
system_profiler SPUSBDataType解析文本输出是更稳的选择
真正麻烦的从来不是怎么读,而是设备刚插上时系统还没完成枚举、或者多个进程同时抢设备句柄——这类竞态问题没法靠单次调用解决,得加重试和延迟。










