Могу ли я использовать SetupDiEnumDeviceInterfaces для получения DevicePath из SetupDiGetDeviceInterfaceDetail, когда неизвестен InterfaceClassGUID?

Обзор...

Я прочитал Как получить GUID интерфейса устройства для устройства? и Как открыть дескриптор устройства, используя его идентификатор экземпляра устройства?, но я все еще не понимаю, как мне (и нужно ли вообще) использовать SetupDiEnumDeviceInterfaces в паре с SetupDiGetDeviceInterfaceDetail, чтобы получить DevicePath, который можно открыть с помощью CreateFile для доступа s устройство, когда нет устройства класс интерфейса известен GUID. Мой вопрос основан на статье MSDN здесь и здесь, которые полагаются на эти функции.

Подробнее…

Высокий уровень моей проблемы заключается в том, что у меня есть аудиоустройство USB, которое мне нужно для отправки команд передачи управления. Для этого я хочу использовать версию API, и для этого мне нужно получить дескриптор устройства через CreateFile. К сожалению, нет файла .inf, связанного с устройством, поэтому нет известного GUID класса интерфейса устройства. Если устройство подключить, Windows связывается с ним usbaudio.sys в качестве драйвера. Чтобы начать общение через WinUSB, я использую libwdi для установки WinUSB в качестве драйвера устройства, чтобы я мог общаться с через WinUSB API. Чтобы выполнить установку WinUSB, libwdi динамически создает пару файлов .cat и .inf с собственной подписью, для которой, к сожалению, не определен класс интерфейса устройства. На самом деле в файле INF есть следующее:

[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver

Итак, несмотря на то, что я заменил usbaudio.sys на winusb.sys, я не могу связаться с устройством.

Сначала я подумал, может быть, мне стоит попробовать использовать GUID_DEVINTERFACE_USB_DEVICE, полагая, что это WinUSB и поэтому рассматривается как обычное USB-устройство. Но если я вызову

SetupDiEnumDeviceInterfaces(_deviceList,
   &devInfo,
   &GUID_DEVINTERFACE_USB_DEVICE,
   0,
   &usbInterface)

это не удается, и GetLastError немедленно возвращает 259 или ERROR_NO_MORE_ITEMS. Я предполагаю, что это означает, что он не реализует интерфейс?

Итак, в общем, когда не известен guid класса интерфейса, могу ли я использовать вышеупомянутые функции в любой форме, чтобы получить полный путь к устройству? Спасибо заранее за ваше время.


person Ben    schedule 13.05.2021    source источник


Ответы (1)


Да, сначала вам нужно получить набор информации об устройстве для устройств, реализующих интерфейс через SetupDiGetClassDevs, затем выбрать одно из устройств и прочитать его данные интерфейса устройства, а затем использовать их для получения сведений об интерфейсе устройства, которые содержит путь к устройству.

Пример:

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <usbioctl.h>
#include <stdio.h>

BOOL DevicePath(_In_ LPCGUID interfaceGuid, DWORD instance)
{
    BOOL result = FALSE;
    PSP_DEVICE_INTERFACE_DETAIL_DATA_W devInterfaceDetailData = NULL;

    HDEVINFO hDevInfo = SetupDiGetClassDevsW(interfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if(hDevInfo == INVALID_HANDLE_VALUE)
        goto cleanup;

    SP_DEVICE_INTERFACE_DATA devInterfaceData;
    devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    if(!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, interfaceGuid, instance, &devInterfaceData))
        goto cleanup;

    // Call this with an empty buffer to the required size of the structure.
    ULONG requiredSize;
    SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, NULL, 0, &requiredSize, NULL);
    if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        goto cleanup;

    devInterfaceDetailData = malloc(requiredSize);
    if(!devInterfaceDetailData)
        goto cleanup;

    devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    if(!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL))
        goto cleanup;

    wprintf(L"%s\n", devInterfaceDetailData->DevicePath);
    result = TRUE;

cleanup:
    if(hDevInfo != INVALID_HANDLE_VALUE)
        SetupDiDestroyDeviceInfoList(hDevInfo);
    free(devInterfaceDetailData);
    return result;
}

int main()
{
    for(DWORD i = 0; DevicePath(&GUID_DEVINTERFACE_USB_DEVICE, i); ++i)
       ;
}
person Mark Tolonen    schedule 14.05.2021
comment
Замечательно! Это именно то, что я искал. Спасибо большое. - person Ben; 14.05.2021
comment
... оглядываясь назад, я не понимал, как работают наборы информации об устройстве, и это показало это. По сути, элементы информации об устройстве имеют связанный список подключенных к ним интерфейсов, в моем коде, несмотря на захват правильного устройства, я делаю следующее для поиска интерфейса USB: 0-й элемент в связанном списке для devInfo не обязательно реализует этот интерфейс, поэтому он не работает. Сидя в петле, как вы, решили это. Потрясающий. - person Ben; 14.05.2021
comment
@ Бен Не совсем. SetupDiGetClassDevs запрашивает устройства с интерфейсом, поэтому все элементы имеют интерфейс. Цикл просто перебирает все экземпляры. Я мог бы поместить цикл for внутрь функции DevicePath и вызывать SetupDiGetClassDevs только один раз. - person Mark Tolonen; 14.05.2021
comment
@Ben Вы не показали свой вызов SetupDiGetClassDevs, но я предполагаю, что вы передали NULL для первого параметра и получили все устройства, а не только те, которые имеют нужный вам интерфейс. - person Mark Tolonen; 14.05.2021
comment
....ХОРОШО. Я перечитал то, что вы сказали: он проходит через ЭКЗЕМПЛЯРЫ, а не ИНТЕРФЕЙСЫ. Теперь я понимаю. Я понимаю. Большое спасибо, что нашли время ответить и просветить. - person Ben; 14.05.2021