Как получить USB_DEVICE_DESCRIPTOR с указанием пути к устройству

Я смог перечислить USB-устройства, используя SetupAPI, и я посмотрел на приложение usbview из WDK, но я все еще не могу понять, как получить USB_DEVICE_DESCRIPTOR.

  • Я бы предпочел не использовать WMI.
  • DeviceIoControl - это то, что использует пример приложения usbview, но это действительно работает, только если вы перечисляете устройства на концентраторе. Я полагаю, что если мне удастся добраться до родительского концентратора (и порта), указав путь к устройству (или Id), этот метод может работать, но я также не смог определить, как это сделать.
  • У меня есть набор устройств, для которых я хотел бы получить дескриптор. Некоторые из них являются HID, и, возможно, некоторые из них являются устройствами WinUsb.sys. Если это устройства WinUsb, я могу использовать WinUsb_GetDescriptor, но это не сработает для HID (и я не знаю, как отличить их от Id или Path... Интерфейсный класс, я полагаю?).
  • Я мог бы использовать SetupDiGetDeviceRegistryProperty, но в списке доступных свойств я вижу строку "Производитель", но не идентификатор поставщика.
  • Я мог бы проанализировать это значение из пути к устройству или идентификатора устройства, но это выглядит как... взлом. Это то, что люди делают? Кроме того, это все еще заставляет меня переходить к другим методам, если мне нужны другие поля, такие как "Производитель", где, если бы я мог просто получить весь USB_DEVICE_DESCRIPTOR, я думаю, у меня было бы все, что мне нужно.
  • Очевидно, LibUsb.Net поддерживает только устройства WinUsb. Вот как это выглядит, чтобы получить дескриптор.
  • Очевидно, у WinRT есть несколько новых API, и поэтому приложения Магазина Windows имеют хороший способ получить дескриптор. Но это определенно не приложение для Магазина Windows, и я не знаю, есть ли другой способ использовать более новые API.

Может кто-то указать мне верное направление? Разве просто невозможно получить эту информацию из WinAPI хорошим способом без запуска в Hub?

1 ответ

Решение

Лучше всего было бы извлечь информацию из пути к устройству и использовать функции SetupDi для получения других фрагментов. Насколько я знаю, путь к устройству всегда следует одному и тому же соглашению. то есть:

"\\? \ usb # vid_0000& pid_1111#SERIAL# {GUID}", где 0000 - это VID, а 1111 - это PID в виде шестнадцатеричной строки. SERIAL - это либо серийный номер, предоставленный аппаратным обеспечением, либо серийный номер, назначенный операционной системой.

Я лично нашел случай, когда я абсолютно хотел получить дескриптор устройства, чтобы вытащить серийник таким образом. В некоторых случаях ОС не распознавала серийный номер, предоставленный моим оборудованием. Я исправил это со стороны аппаратного обеспечения, но я все еще хотел разместить старое оборудование на стороне ПК. Ниже мой подход. Может быть что-то и получше, но это лучшее, что я придумал до сих пор. Вы все еще можете считать это "взломом", хотя.

  1. Вызовите SetupDiGetClassDevs(), чтобы настроить нужный DeviceInfoSet
  2. Получить информацию о вашем устройстве с помощью SetupDiEnumDeviceInfo()
  3. Вызовите функцию SetupDiGetDeviceRegistryProperty() с помощью функции SPDRP_LOCATION_INFORMATION, чтобы получить информацию о местоположении. Эта строка должна выглядеть как "Port_#0001.Hub_#0001". Разобрать эту строку, чтобы получить номер порта, где находится ваше устройство. (Я предполагаю, что это значение - основание 10, но я еще не проверил это)
  4. Вызовите CM_Get_Parent(), чтобы получить значение указателя узла устройства родителя (концентратор)
  5. Вызовите функцию SetupDiGetClassDevs() с GUID {0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8}}, чтобы получить все концентраторы в вашей системе. Этот GUID должен быть определен как GUID_DEVINTERFACE_USB_HUB в usbiodef.h.
  6. Выполните итерацию по списку устройств с помощью SetupDiEnumDeviceInfo(). Остановитесь, как только DevInst станет равным значению, полученному на шаге 4.
  7. Вызовите SetupDiGetDeviceInterfaceDetail() для индекса, найденного на шаге 6.
  8. Вызовите CreateFile() для DevicePath, полученного на шаге 7.
  9. Вызовите DeviceIoControl(), используя файл, созданный на шаге 8, и номер порта, полученный на шаге 3, в качестве индекса соединения.

-РЕДАКТИРОВАТЬ-

Как отметил Бен в комментариях, вы можете пропустить шаги 5, 6 и 7, используя CM_Get_Device_ID на родительском узле dev, полученном на шаге 4. Измените косую черту (\) в этой строке на фунты (#). Добавьте "\\?\" И добавьте "#{f18a0e88-c30c-11d0-8815-00a0c906bed8}". Используйте его в качестве пути к устройству на шаге 8. Это позволит избежать итерации всех устройств-концентраторов в вашей системе:)

Другие вопросы по тегам