Как получить 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 - это либо серийный номер, предоставленный аппаратным обеспечением, либо серийный номер, назначенный операционной системой.
Я лично нашел случай, когда я абсолютно хотел получить дескриптор устройства, чтобы вытащить серийник таким образом. В некоторых случаях ОС не распознавала серийный номер, предоставленный моим оборудованием. Я исправил это со стороны аппаратного обеспечения, но я все еще хотел разместить старое оборудование на стороне ПК. Ниже мой подход. Может быть что-то и получше, но это лучшее, что я придумал до сих пор. Вы все еще можете считать это "взломом", хотя.
- Вызовите SetupDiGetClassDevs(), чтобы настроить нужный DeviceInfoSet
- Получить информацию о вашем устройстве с помощью SetupDiEnumDeviceInfo()
- Вызовите функцию SetupDiGetDeviceRegistryProperty() с помощью функции SPDRP_LOCATION_INFORMATION, чтобы получить информацию о местоположении. Эта строка должна выглядеть как "Port_#0001.Hub_#0001". Разобрать эту строку, чтобы получить номер порта, где находится ваше устройство. (Я предполагаю, что это значение - основание 10, но я еще не проверил это)
- Вызовите CM_Get_Parent(), чтобы получить значение указателя узла устройства родителя (концентратор)
- Вызовите функцию SetupDiGetClassDevs() с GUID {0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8}}, чтобы получить все концентраторы в вашей системе. Этот GUID должен быть определен как GUID_DEVINTERFACE_USB_HUB в usbiodef.h.
- Выполните итерацию по списку устройств с помощью SetupDiEnumDeviceInfo(). Остановитесь, как только DevInst станет равным значению, полученному на шаге 4.
- Вызовите SetupDiGetDeviceInterfaceDetail() для индекса, найденного на шаге 6.
- Вызовите CreateFile() для DevicePath, полученного на шаге 7.
- Вызовите DeviceIoControl(), используя файл, созданный на шаге 8, и номер порта, полученный на шаге 3, в качестве индекса соединения.
-РЕДАКТИРОВАТЬ-
Как отметил Бен в комментариях, вы можете пропустить шаги 5, 6 и 7, используя CM_Get_Device_ID на родительском узле dev, полученном на шаге 4. Измените косую черту (\) в этой строке на фунты (#). Добавьте "\\?\" И добавьте "#{f18a0e88-c30c-11d0-8815-00a0c906bed8}". Используйте его в качестве пути к устройству на шаге 8. Это позволит избежать итерации всех устройств-концентраторов в вашей системе:)