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.
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:
I did that here . There was a bunch of things you need to keep in mind - like composite USB device support. Main algo was something like this:
m_DeviceInterfacePath = SearchParentDeviceInterface(hidDeviceInstanceId, &GUID_DEVINTERFACE_USB_DEVICE);
m_DeviceInstanceId = GetDeviceFromInterface(m_DeviceInterfacePath);
DEVINST devNodeHandle = OpenDevNode(m_DeviceInstanceId);
// open handle to wake up device from S3 suspend state
ScopedHandle usbInterfaceHandle = OpenDeviceInterface(m_DeviceInterfacePath);
// device index in parent USB hub
// https://docs.microsoft.com/windows-hardware/drivers/ddi/wdm/ns-wdm-_device_capabilities#usb
m_UsbPortIndex = PropertyDataCast<ULONG>(GetDevNodeProperty(devNodeHandle, &DEVPKEY_Device_Address, DEVPROP_TYPE_UINT32));
std::vector<std::string> usbDeviceCompatibleIds = PropertyDataCast<std::vector<std::string>>(GetDevNodeProperty(devNodeHandle, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST));
for (const std::string& usbCompatibleId : usbDeviceCompatibleIds)
{
stringutils::ci_string tmp(usbCompatibleId.data(), usbCompatibleId.size());
// https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
if (tmp.find("USB\\COMPOSITE") == stringutils::ci_string::npos)
continue;
// Its Composite USB device
// Need to acquire interface number in parent USB device
// https://docs.microsoft.com/windows-hardware/drivers/usbcon/usb-common-class-generic-parent-driver
m_UsbCompositeDeviceInstanceId = GetParentDevice(hidDeviceInstanceId);
if (!GetInterfaceNumber(m_UsbCompositeDeviceInstanceId, m_UsbInterfaceNumber))
{
// Try again
m_UsbCompositeDeviceInstanceId = GetParentDevice(m_UsbCompositeDeviceInstanceId);
if (!GetInterfaceNumber(m_UsbCompositeDeviceInstanceId, m_UsbInterfaceNumber))
{
DBGPRINT("UsbDevice: cannot get interface number");
return;
}
}
break;
}
std::string usbHubInterface = SearchParentDeviceInterface(m_DeviceInstanceId, &GUID_DEVINTERFACE_USB_HUB);
if (usbHubInterface.empty())
return;
ScopedHandle hubInterfaceHandle = OpenDeviceInterface(usbHubInterface, true);
USB_DEVICE_DESCRIPTOR deviceDescriptor;
if (!GetDeviceDescriptor(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor))
return;
m_VendorId = deviceDescriptor.idVendor;
m_ProductId = deviceDescriptor.idProduct;
m_VersionNumber = deviceDescriptor.bcdDevice;
// Assume that we are always using first configuration
const UCHAR configurationIndex = 0;
if (!GetFullConfigurationDescriptor(hubInterfaceHandle, m_UsbPortIndex, configurationIndex, m_ConfigurationDescriptor))
return;
// Search for interface descriptor
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = nullptr;
if (!SearchInterfaceDescriptor(m_ConfigurationDescriptor, m_UsbInterfaceNumber, interfaceDescriptor))
return;
std::wstring stringBuffer;
// Get the array of supported Language IDs, which is returned in String Descriptor 0
if (!GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, 0, 0, stringBuffer))
return;
// Use first supported language
USHORT languageID = stringBuffer[0];
if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor.iManufacturer, languageID, stringBuffer))
m_Manufacturer = utf8::narrow(stringBuffer);
// Get interface name instead of whole product name, if present
UCHAR productStringIndex = interfaceDescriptor->iInterface ? interfaceDescriptor->iInterface : deviceDescriptor.iProduct;
if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, productStringIndex, languageID, stringBuffer))
m_Product = utf8::narrow(stringBuffer);
if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor.iSerialNumber, languageID, stringBuffer))
m_SerialNumber = utf8::narrow(stringBuffer);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.