如何在给定设备路径的情况下获取 USB_DEVICE_DESCRIPTOR

Posted

技术标签:

【中文标题】如何在给定设备路径的情况下获取 USB_DEVICE_DESCRIPTOR【英文标题】:How do I obtain USB_DEVICE_DESCRIPTOR given a device path 【发布时间】:2015-01-18 05:33:05 【问题描述】:

我已经能够使用 SetupAPI 枚举 USB 设备,并且我已经查看了 WDK 中的 usbview 应用程序,但我仍然不知道如何获取 USB_DEVICE_DESCRIPTOR。

我宁愿避免使用 WMI。 DeviceIoControl 是示例应用程序 usbview 使用的,但只有在您枚举集线器上的设备时才真正起作用。我想如果我可以在给定设备路径(或 ID)的情况下到达父集线器(和端口),这种方法可能有效,但我也无法确定如何执行此操作。 我有多种设备,我想为其获取描述符。其中有些是 HID,有些可能是 WinUsb.sys 设备。如果它们是 WinUsb 设备,我可以使用 WinUsb_GetDescriptor,但这不适用于 HID(而且我不知道如何从 Id 或 Path...Interface 类中区分它们?我猜?)。 我可以使用 SetupDiGetDeviceRegistryProperty,但在可用属性列表中,我可以看到制造商字符串,但看不到供应商 ID。 我可以从设备路径或设备 ID 中解析这个值,但这似乎有点……hack-ish。这只是人们所做的吗?此外,如果我想要制造商等其他领域,它仍然会让我采用其他方法,如果我可以得到整个 USB_DEVICE_DESCRIPTOR,我想我会拥有我需要的一切。 LibUsb.Net 显然只支持 WinUsb 设备。这就是它似乎获得描述符的方式。 显然 WinRT 有一些新的 API,因此 Windows 应用商店应用程序有一个很好的方法来获取描述符。但这绝对不是 Windows Store 应用,我不知道还有其他方法可以使用较新的 API。

谁能指出我正确的方向?如果不从 Hub 开始,是否无法以一种很好的方式从 WinAPI 获取这些信息?

【问题讨论】:

似乎可能有帮助:microsoft.public.development.device.drivers.narkive.com/… 和 SetupDiGetDevicePropertyDEVPKEY_Device_Address CM_Get_DevNode_Property。获得端口号后,您可以使用CM_Get_Parent 获取父 USB 集线器,打开它,向它发送 IOCTL,请求有关该端口的枚举设备的更多信息。 您能提及 WinRT API 吗?可以通过 C++/WRL 将它们用于本机 win32 应用程序。 【参考方案1】:

最好的办法是从设备路径中提取信息并使用 SetupDi 函数获取其他零碎信息。据我所知,设备路径始终遵循相同的约定。即:

"\\?\usb#vid_0000&pid_1111#SERIAL#GUID" 其中 0000 是 VID,1111 是十六进制字符串形式的 PID。 SERIAL 是硬件提供的序列号或操作系统分配的序列号。

我个人发现了一个我绝对想获取设备描述符以便以这种方式提取序列的实例。在某些情况下,操作系统无法识别我的硬件提供的序列号。我在硬件端解决了这个问题,但我仍然想在 PC 端容纳旧硬件。下面是我的方法。可能有更好的东西,但这是迄今为止我想出的最好的。不过,您可能仍然认为它是“hack-ish”。

    调用 SetupDiGetClassDevs() 设置所需的 DeviceInfoSet 使用 SetupDiEnumDeviceInfo() 获取您的设备信息数据 使用 SPDRP_LOCATION_INFORMATION 调用 SetupDiGetDeviceRegistryProperty() 以获取位置信息。此字符串应类似于“Port_#0001.Hub_#0001”。解析此字符串以获取您的设备所在的端口号。 (我假设这个值是以 10 为底,但我还没有验证) 调用CM_Get_Parent()获取父(集线器)的设备节点指针值 使用 GUID 0xf18a0e88, 0xc30c, 0x11d0, 0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8 调用 SetupDiGetClassDevs() 以获取系统上的所有集线器。该 GUID 应在 usbiodef.h 中定义为 GUID_DEVINTERFACE_USB_HUB。 使用 SetupDiEnumDeviceInfo() 遍历设备列表。一旦 DevInst 等于步骤 4 中获得的值,就停止。 在第 6 步中找到的索引上调用 SetupDiGetDeviceInterfaceDetail()。 在步骤 7 中获得的 DevicePath 上调用 CreateFile()。 使用在步骤 8 中创建的文件和在步骤 3 中获取的端口号作为连接索引调用 DeviceIoControl()。

-编辑-

正如 Ben 在 cmets 中指出的那样,您可以通过在步骤 4 中获得的父开发节点上使用 CM_Get_Device_ID 跳过步骤 5、6 和 7。将此字符串中的斜杠 (\) 更改为磅 (#)。附加“\\?\”,然后附加“#f18a0e88-c30c-11d0-8815-00a0c906bed8”。在第 8 步中将其用作您的设备路径。这样可以避免遍历系统上的所有集线器设备 :)

【讨论】:

我认为从第 4 步到第 6 步有更好的方法,但我现在不记得是什么了。 也许CM_Get_Device_ID 在父级的DEVNODE* 上以获取设备实例ID,然后是SetupDiOpenDeviceInfo,它会将您带到SetupDiEnumDeviceInterfaces 需要的PSP_DEVINFO_DATA 本,您可能正在做一些事情。我从 CM_Get_Device_ID 得到的值是“USB\VID_050D&PID_0237\7&85D56EA&0&5”。路径应该是“\\?\usb#vid_050d&pid_0237#7&85d56ea&0&5#f18a0e88-c30c-11d0-8815-00a0c906bed8”。如果我们假设中心 GUID,则可以生成该路径。 这和我最后采用的方法类似。除了...我认为正如 Ben 所说,我不必获取所有集线器的列表。不幸的是,我得到了我需要工作的东西,把它交给了,从那以后我没有想太多,所以我不太记得我对那部分做了什么...... 您必须使用集线器句柄的代码 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX 调用 DeviceIoControl,而不是使用设备句柄,对吧?

以上是关于如何在给定设备路径的情况下获取 USB_DEVICE_DESCRIPTOR的主要内容,如果未能解决你的问题,请参考以下文章

如何在给定完整路径的情况下导入模块?

ubuntu 下如何获取USB接口相机的uri路径

在给定“路径”的情况下修改嵌套字典中的元素

如何在给定进程名称的情况下获取 pid

使用java API如何获取给定路径的HDF文件结构

如何在给定上下文的情况下获取布局充气器?