Получить букву USB-накопителя по пути или дескриптору устройства

Моя цель — написать c-dll (скомпилированную с помощью MinGW), которая способна искать определенные модели USB-накопителей, подключенных к компьютеру, и выдавать серийный номер, идентификатор поставщика, идентификатор продукта и букву диска. Я искал в Интернете несколько часов, но не смог найти подход, который работает для меня.

Я использую Setup Api, чтобы получить список всех подключенных USB-устройств. Для каждого USB-устройства я получаю путь, который выглядит следующим образом: \?\usb#vid_048d&pid_1172#00000020370220#{a5dcbf10-6530-11d2-901f-00c04fb951ed} Из этой строки я могу получить идентификатор поставщика, идентификатор продукта и серийный номер, который мне нужен.

Теперь моя проблема заключается в том, чтобы определить букву диска USB-накопителя, связанного с этим путем к устройству. Во время моего интернет-исследования я несколько раз находил следующий подход (например, здесь http://oroboro.com/usb-serial-number/): как только путь к устройству найден, USB-накопитель должен быть открыт CreateFile. Дескриптор, возвращаемый этой функцией, можно использовать для получения номера устройства функцией DeviceIOControl с IOCTL_STORAGE_GET_DEVICE_NUMBER. После этого можно использовать функцию CreateFile, чтобы открыть каждую букву диска (начиная с a:) ​​и попытаться получить номер устройства так же, как описано выше. Как только тот же номер устройства будет найден снова, устанавливается связь между путем к устройству и буквой диска.

Моя проблема в том, что вызов IOCTL_STORAGE_GET_DEVICE_NUMBER не работает. Функция DeviceIOControl возвращает код ошибки 50, что означает «Запрос не поддерживается».

Я не могу создать связь между путем устройства USB-накопителя и буквой диска. Я пробовал несколько вызовов IOCTL_STORAGE and IOCTL_VOLUME, но ни один из них не работал для USB-накопителей, которые я пробовал. Я также читал на другом форуме, что у людей были проблемы с результатами функции DeviceIOControl. На одних компьютерах он возвращал желаемый результат, а на других создавал проблемы. Есть ли другой способ достичь моей цели?

Я уже заглянул в реестр, где тоже могу найти нужные данные. Но снова у меня возникла проблема с созданием связи между путем к устройству и буквой диска. Я не хотел бы использовать WMI. Я читал, что он до сих пор не поддерживается MinGW. У меня есть реализация для всего этого на C#, где очень легко получить нужную информацию, но теперь мне также нужен тот, который создан с неуправляемым кодом и может использоваться для замены c-dll, также включенного в проекты Delphi.

Буду признателен за любые предложения по решению моей проблемы.

С уважением, Флориан

А вот код, если кому интересно. Позиция с таким комментарием "//ВОТ ГДЕ Я ХОЧУ ПОЛУЧИТЬ НОМЕР УСТРОЙСТВА!!!" где запрос номера устройства будет использоваться, если он будет работать.

typedef struct ty_TUSB_Device
{
    PSP_DEVICE_INTERFACE_DETAIL_DATA    deviceDetailData;
    char                                devicePath[300];

}TUSB_Device;

int
GetUSBDevices (TUSB_Device *devList[], int size)
{
    HANDLE      hHCDev;

    HDEVINFO                         deviceInfo;
    SP_DEVICE_INTERFACE_DATA         deviceInfoData;
    ULONG                            index;
    ULONG                            requiredLength;
    int                              devCount = 0;
    //SP_DEVINFO_DATA                DevInfoData;




    // Now iterate over host controllers using the new GUID based interface
    //
    deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
                                     NULL,
                                     NULL,
                                     (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));

    if (deviceInfo != INVALID_HANDLE_VALUE)
    {
        deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

        for (index=0;
             SetupDiEnumDeviceInterfaces(deviceInfo,
                                         0,
                                         (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
                                         index,
                                         &deviceInfoData);
             index++)
        {
            SetupDiGetDeviceInterfaceDetail(deviceInfo,
                                            &deviceInfoData,
                                            NULL,
                                            0,
                                            &requiredLength,
                                            NULL);

            //allocate memory for pointer to TUSB_Device structure
            devList[devCount] = malloc(sizeof(TUSB_Device));

            devList[devCount]->deviceDetailData = GlobalAlloc(GPTR, requiredLength);

            devList[devCount]->deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            SetupDiGetDeviceInterfaceDetail(deviceInfo,
                                            &deviceInfoData,
                                            devList[devCount]->deviceDetailData,
                                            requiredLength,
                                            &requiredLength,
                                            NULL);

            //open the usb device
            hHCDev = CreateFile(devList[devCount]->deviceDetailData->DevicePath,
                                GENERIC_WRITE,
                                FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                0,
                                NULL);


            // If the handle is valid, then we've successfully found a usb device
            //
            if (hHCDev != INVALID_HANDLE_VALUE)
            {
                strncpy(devList[devCount]->devicePath, devList[devCount]->deviceDetailData->DevicePath, sizeof(devList[devCount]->devicePath));

                //HERE IS WHERE I WOULD LIKE TO GET THE DEVICE NUMBER!!!

                CloseHandle(hHCDev);

                devCount++;
            }

            //GlobalFree(devList[devCount]->deviceDetailData);

        }

        SetupDiDestroyDeviceInfoList(deviceInfo);
    }

    return devCount;
}

person fotten    schedule 03.07.2014    source источник


Ответы (1)


Я узнал, в чем моя проблема. Из того, что я читал в Интернете, кажется, что у других людей такие же проблемы, как и у меня, поэтому я опубликую свое решение.

Все дело в том, что с помощью SetupApi можно получить разные значения пути для USB-устройства. Все значения пути могут быть использованы для получения дескриптора этого устройства, но, очевидно, существуют различия в том, что можно сделать с дескриптором. Моя ошибка заключалась в том, чтобы использовать GUID_DEVINTERFACE_USB_DEVICE для вывода списка устройств. Я обнаружил, что когда я использую GUID_DEVINTERFACE_DISK, я получаю другое значение пути, которое позволяет мне запрашивать номер устройства. Таким образом, я могу получить ссылку на букву диска. Это значение пути, полученное с помощью GUID_DEVINTERFACE_DISK, также содержит серийный номер, но не идентификатор поставщика и продукта. Но поскольку оба значения пути содержат серийный номер, получить их оба и построить отношение не составит труда.

Я протестировал код с Windows XP, 7 и 8, и он отлично работает. Необходимо изменить только код FileCreate из приведенного выше примера кода (замените GENERIC_WRITE на 0). В противном случае требуются права администратора или режим совместимости.

Я не пытался выяснить, что на самом деле означают эти разные значения GUID. Кто-то с более глубокими знаниями в этой области, вероятно, мог бы дать лучшее объяснение.

С уважением, Флориан

person fotten    schedule 08.07.2014
comment
Предположительно USB-устройство также является родителем дискового устройства, поэтому вы также можете связать их таким образом. - person Ben Voigt; 20.01.2015