如何在给定设备路径的情况下获取 USB_DEVICE_DESCRIPTOR
How do I obtain USB_DEVICE_DESCRIPTOR given a device path
我已经能够使用 SetupAPI 枚举 USB 设备,并且我查看了 WDK 中的 usbview 应用程序,但我仍然无法弄清楚如何获取 USB_DEVICE_DESCRIPTOR。
- 我宁愿避免使用 WMI。
- DeviceIoControl 是示例应用程序 usbview 使用的内容,但仅当您在集线器上枚举设备时才有效。我想如果我可以在给定设备路径(或 Id)的情况下到达父集线器(和端口),则此方法可能有效,但我也无法确定如何执行此操作。
- 我有多种设备想要获取描述符。其中一些是 HID,有些可能是 WinUsb.sys 设备。如果它们是 WinUsb 设备,我可以使用 WinUsb_GetDescriptor,但这不适用于 HID(而且我不知道如何从 Id 或 Path...Interface class 中区分它们我猜?)。
- 我可以使用 SetupDiGetDeviceRegistryProperty,但在可用属性列表中,我可以看到制造商字符串,但看不到供应商 ID。
- 我可能会从设备路径或设备 ID 中解析此值,但这似乎有点……hack-ish。那只是人们所做的吗?此外,如果我想要像制造商这样的其他字段,我仍然可以使用其他方法,如果我能得到整个 USB_DEVICE_DESCRIPTOR 我想我会拥有我需要的一切。
- LibUsb.Net 显然只支持 WinUsb 设备。这似乎是如何获得描述符的。
- 显然 WinRT 有一些新的 API,因此 Windows 商店应用程序有一种获取描述符的好方法。但这绝对不是 Windows 商店应用程序,我不知道还有其他方法可以使用较新的 API。
任何人都可以指出我正确的方向吗?如果不从 Hub 开始,就无法以一种很好的方式从 WinAPI 获取此信息吗?
最好的办法是从设备路径中提取信息并使用 SetupDi 函数获取其他零碎信息。据我所知,设备路径始终遵循相同的约定。即:
"\\?\usb#vid_0000&pid_1111#SERIAL#{ GUID}"
其中 0000 是 VID,1111 是十六进制字符串形式的 PID。 SERIAL 是硬件提供的序列号或 OS 分配的序列值。
我个人发现了一个实例,我绝对想获取设备描述符以便以这种方式拉取序列号。在某些情况下,OS 无法识别我的硬件提供的序列号。我在硬件方面修复了这个问题,但我仍然想在 PC 端容纳旧硬件。以下是我的方法。可能有更好的东西,但这是迄今为止我想出的最好的。不过,您可能仍然认为它是 "hack-ish"。
- 调用 SetupDiGetClassDevs() 来设置您想要的 DeviceInfoSet
- 使用 SetupDiEnumDeviceInfo() 获取您的设备信息数据
- 使用 SPDRP_LOCATION_INFORMATION 调用 SetupDiGetDeviceRegistryProperty() 以获取位置信息。此字符串应类似于 "Port_#0001.Hub_#0001"。解析此字符串以获取您的设备所在的端口号。 (我假设这个值是以10为底,但我还没有验证过)
- 调用CM_Get_Parent()获取parent(hub)的设备节点指针值
- 使用 {0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8}} 的 GUID 调用 SetupDiGetClassDevs() 以获取系统上的所有集线器。该 GUID 应在 usbiodef.h.
中定义为 GUID_DEVINTERFACE_USB_HUB
- 使用 SetupDiEnumDeviceInfo() 遍历设备列表。一旦 DevInst 等于步骤 4 中获得的值,就停止。
- 对在步骤 6 中找到的索引调用 SetupDiGetDeviceInterfaceDetail()。
- 在步骤 7 中获得的 DevicePath 上调用 CreateFile()。
- 使用第 8 步中创建的文件和第 3 步中获取的端口号作为连接索引调用 DeviceIoControl()。
-编辑-
正如 Ben 在评论中指出的那样,您可以通过在步骤 4 中获得的父级开发节点上使用 CM_Get_Device_ID 来跳过步骤 5、6 和 7。将此字符串中的斜杠 (\) 更改为磅 (#)。前置“\\?\”,然后附加“#{f18a0e88-c30c-11d0-8815-00a0c906bed8}”。在第 8 步中将其用作您的设备路径。这样可以避免遍历系统上的所有集线器设备:)
我已经能够使用 SetupAPI 枚举 USB 设备,并且我查看了 WDK 中的 usbview 应用程序,但我仍然无法弄清楚如何获取 USB_DEVICE_DESCRIPTOR。
- 我宁愿避免使用 WMI。
- DeviceIoControl 是示例应用程序 usbview 使用的内容,但仅当您在集线器上枚举设备时才有效。我想如果我可以在给定设备路径(或 Id)的情况下到达父集线器(和端口),则此方法可能有效,但我也无法确定如何执行此操作。
- 我有多种设备想要获取描述符。其中一些是 HID,有些可能是 WinUsb.sys 设备。如果它们是 WinUsb 设备,我可以使用 WinUsb_GetDescriptor,但这不适用于 HID(而且我不知道如何从 Id 或 Path...Interface class 中区分它们我猜?)。
- 我可以使用 SetupDiGetDeviceRegistryProperty,但在可用属性列表中,我可以看到制造商字符串,但看不到供应商 ID。
- 我可能会从设备路径或设备 ID 中解析此值,但这似乎有点……hack-ish。那只是人们所做的吗?此外,如果我想要像制造商这样的其他字段,我仍然可以使用其他方法,如果我能得到整个 USB_DEVICE_DESCRIPTOR 我想我会拥有我需要的一切。
- LibUsb.Net 显然只支持 WinUsb 设备。这似乎是如何获得描述符的。
- 显然 WinRT 有一些新的 API,因此 Windows 商店应用程序有一种获取描述符的好方法。但这绝对不是 Windows 商店应用程序,我不知道还有其他方法可以使用较新的 API。
任何人都可以指出我正确的方向吗?如果不从 Hub 开始,就无法以一种很好的方式从 WinAPI 获取此信息吗?
最好的办法是从设备路径中提取信息并使用 SetupDi 函数获取其他零碎信息。据我所知,设备路径始终遵循相同的约定。即:
"\\?\usb#vid_0000&pid_1111#SERIAL#{ GUID}" 其中 0000 是 VID,1111 是十六进制字符串形式的 PID。 SERIAL 是硬件提供的序列号或 OS 分配的序列值。
我个人发现了一个实例,我绝对想获取设备描述符以便以这种方式拉取序列号。在某些情况下,OS 无法识别我的硬件提供的序列号。我在硬件方面修复了这个问题,但我仍然想在 PC 端容纳旧硬件。以下是我的方法。可能有更好的东西,但这是迄今为止我想出的最好的。不过,您可能仍然认为它是 "hack-ish"。
- 调用 SetupDiGetClassDevs() 来设置您想要的 DeviceInfoSet
- 使用 SetupDiEnumDeviceInfo() 获取您的设备信息数据
- 使用 SPDRP_LOCATION_INFORMATION 调用 SetupDiGetDeviceRegistryProperty() 以获取位置信息。此字符串应类似于 "Port_#0001.Hub_#0001"。解析此字符串以获取您的设备所在的端口号。 (我假设这个值是以10为底,但我还没有验证过)
- 调用CM_Get_Parent()获取parent(hub)的设备节点指针值
- 使用 {0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8}} 的 GUID 调用 SetupDiGetClassDevs() 以获取系统上的所有集线器。该 GUID 应在 usbiodef.h. 中定义为 GUID_DEVINTERFACE_USB_HUB
- 使用 SetupDiEnumDeviceInfo() 遍历设备列表。一旦 DevInst 等于步骤 4 中获得的值,就停止。
- 对在步骤 6 中找到的索引调用 SetupDiGetDeviceInterfaceDetail()。
- 在步骤 7 中获得的 DevicePath 上调用 CreateFile()。
- 使用第 8 步中创建的文件和第 3 步中获取的端口号作为连接索引调用 DeviceIoControl()。
-编辑-
正如 Ben 在评论中指出的那样,您可以通过在步骤 4 中获得的父级开发节点上使用 CM_Get_Device_ID 来跳过步骤 5、6 和 7。将此字符串中的斜杠 (\) 更改为磅 (#)。前置“\\?\”,然后附加“#{f18a0e88-c30c-11d0-8815-00a0c906bed8}”。在第 8 步中将其用作您的设备路径。这样可以避免遍历系统上的所有集线器设备:)