Get USB disk drive letter by device path or handle

别来无恙 提交于 2019-12-02 21:56:42

问题


My goal is to write a c-dll (compiled with MinGW) that is able to search for certain models of USB sticks connected to the computer and deliver the serial number, the vendor ID, the product ID and the drive letter. I have searched on the internet for several hours know but could not find an approach that works for me.

I am using the Setup Api to get a list of all connected USB devices. For each USB device I get a path that looks like this: \?\usb#vid_048d&pid_1172#00000020370220#{a5dcbf10-6530-11d2-901f-00c04fb951ed} From that string I can get the vendor ID, product ID and the serial number I am looking for.

My problem is now to determine the drive letter of the USB drive that is related to this device path. During my internet research I found the following approach multiple times (for example here http://oroboro.com/usb-serial-number/): Once the device path is found, the USB drive must be opened by CreateFile. The handle returned by that function can be used to get the device number by function DeviceIOControl with IOCTL_STORAGE_GET_DEVICE_NUMBER. After that, the CreateFile function could be used to open each drive letter (starting from a:) and try to get the device number the same way like described above. Once the same device number is found again, the relation between device path and drive letter is made.

My Problem is that the IOCTL_STORAGE_GET_DEVICE_NUMBER call is not working. The DeviceIOControl function returns error code 50 which means "The request is not supported".

I am not able to create a link between the device path of a USB stick and the drive letter. I have tried several IOCTL_STORAGE and IOCTL_VOLUME calls but none worked for the USB sticks I tried. I also read in another Forum that people had problems with the results of the DeviceIOControl function. It was returning the desired result on some PCs while it was making trouble on others. Is there another way of achieving my goal?

I already had a look into the registry where I can also find the desired data. But again I had the problem to create the connection between device path and drive letter. I would not like to use the WMI. I have read that it is still not really supported by MinGW. I have a implementaion for all this with C# where it is really easy to get the desired information, but now I also need one that is created with unmanaged code and can be used to replace a c-dll also included in Delphi projects.

I would appreciate any suggestions for a solution to my problem.

Best regards, Florian

And here the code if someone is interested. The position with this comment "//HERE IS WHERE I WOULD LIKE TO GET THE DEVICE NUMBER!!!" is where the request of the device number would be used if it would work.

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;
}

回答1:


I found out what my problem was. From what I read on the internet it seems there where other people having the same problems like me, so I will post my solution.

The whole point is that there are obviously different path values one can obtain for a USB device using the SetupApi. All path values can be used to get a handle to that device, but there are obviously differences about what can be done with the handle. My failure was to use GUID_DEVINTERFACE_USB_DEVICE to list the devices. I found out that when I use GUID_DEVINTERFACE_DISK, I get a different path value that lets me request the device number. That way I am able to get the link to the drive letter. That path value obtained with GUID_DEVINTERFACE_DISK also contains the serial number but not the vendor and product IDs. But since both path values do contain the serial, it is no problem to get them both and build the relation.

I tested the code with Windows XP, 7 and 8 and it works fine. Only the FileCreate code of the code sample above must be adjusted (replace GENERIC_WRITE by 0). Otherwise Administrator rights or compatibility mode are required.

I did not try to find out what these different GUID values really stand for. Someone with a deeper knowledge in this area could probably provide a better explanation.

Best regards, Florian



来源:https://stackoverflow.com/questions/24551507/get-usb-disk-drive-letter-by-device-path-or-handle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!