Search code examples
c#c++windowsusbhid

How do you get the raw descriptor data from a USB HID device in Windows?


How do you get the raw descriptor data from a HID device in Windows?

Background:

I need to get the Manufacturer, Product Name, and Serial Number from a HID device in Windows. I'm using hid.dll to access the devices using the functions seen here. My question is very similar to this one. I am able to get the manufacturer string and product string from SOME HID devices, but most fail to return this data with HidD_GetManufacturerString returning false. However, I KNOW these devices do have the string information in their descriptors because I am able to see it using USBTreeView.

The interesting thing is, even for the devices that do return manufacturer and product names, the values I'm getting through hid.dll are very different from the values I see using the above tool which gets the raw data from the USB device.

For example, an Xbox 360 controller:

Via USB Tree View:
Device Description       : Xbox 360 Controller for Windows
Language 0x0409          : "©Microsoft Corporation"
iProduct                 : 0x02
Language 0x0409          : "Controller"
iSerialNumber            : 0x03
Language 0x0409          : "0843806"

Via hid.dll using HidD_GetManufacturerString, HidD_GetProductString, and HidD_GetSerialNumberString:
Description              : HID-compliant game controller
Product                  : Controller (XBOX 360 Controller for Windows)
Manufacturer             : FAILS
Serial Number            : FAILS

WinUSB is unable to open these devices at all to retrieve this data as they do not use the winusb.sys driver.

1) I don't understand why the values returned by the HidD functions do not match the values in the USB descriptor. 2) I can't find any way to access the raw USB descriptor data for a HID device because I cannot access them with WinUSB.


Edit 1:

Okay, so I've learned a bit more about HID. It seems the data I'm getting through hid.dll is driver-specified data, not data coming from the USB device. HID can apply to devices on transports other than USB as well. So that's fine. Ultimately, what I really want to know is how can I get the USB device when I have the HID device and what API do I use for that. Besides WinUSB which doesn't work, the only thing I can find are kernel-level functions IOCTL. I don't know if that's suitable for a normal, non admin application.


Solution

  • I finally found the solution. The main problem was just associating a HID device to its parent USB device. This is the basic process:

    Assuming you already have the HID device and the SP_DEVINFO_DATA for it:

    1. Enumerate all USB devices as seen here.
    2. Find all children of the USB devices with CM_GetChild and CM_GetSibling.
    3. Compare the known HID device's instance handle (SP_DEVINFO_DATA->DevInst) with each child device's instance handle that was returned by the CM functions to determine which USB device is the parent.
    4. From there, you can get any USB info you want including the descriptor.