通过设备路径或句柄获取 U 盘盘符

Posted

技术标签:

【中文标题】通过设备路径或句柄获取 U 盘盘符【英文标题】:Get USB disk drive letter by device path or handle 【发布时间】:2014-07-03 10:41:59 【问题描述】:

我的目标是编写一个 c-dll(用 MinGW 编译),它能够搜索连接到计算机的特定型号的 U 盘,并提供序列号、供应商 ID、产品 ID 和驱动器号。 我在互联网上搜索了几个小时知道但找不到适合我的方法。

我正在使用 Setup Api 获取所有已连接 USB 设备的列表。对于每个 USB 设备,我得到一个如下所示的路径: \?\usb#vid_048d&pid_1172#00000020370220#a5dcbf10-6530-11d2-901f-00c04fb951ed 从该字符串中,我可以获得供应商 ID、产品 ID 和我正在寻找的序列号。

我现在的问题是确定与此设备路径相关的 USB 驱动器的驱动器号。 在我的互联网研究中,我多次发现以下方法(例如这里http://oroboro.com/usb-serial-number/): 找到设备路径后,USB 驱动器必须由CreateFile 打开。该函数返回的句柄可用于通过函数DeviceIOControlIOCTL_STORAGE_GET_DEVICE_NUMBER 获取设备号。 之后,CreateFile 函数可用于打开每个驱动器号(从 a: 开始)并尝试以与上述相同的方式获取设备号。一旦再次找到相同的设备号,就建立了设备路径和驱动器号之间的关系。

我的问题是IOCTL_STORAGE_GET_DEVICE_NUMBER 呼叫不起作用。 DeviceIOControl 函数返回错误代码 50,表示“不支持请求”。

我无法在 U 盘的设备路径和驱动器号之间创建链接。我尝试了几次IOCTL_STORAGE and IOCTL_VOLUME 电话,但没有一个适用于我尝试过的 USB 记忆棒。 我还在另一个论坛上看到人们对DeviceIOControl 函数的结果有疑问。它在某些 PC 上返回了预期的结果,而在其他 PC 上却遇到了麻烦。 还有其他方法可以实现我的目标吗?

我已经查看了注册表,我还可以在其中找到所需的数据。但是我再次遇到了在设备路径和驱动器号之间创建连接的问题。 我不想使用 WMI。我读过 MinGW 仍然没有真正支持它。 我有一个用 C# 实现所有这些的实现,它很容易获得所需的信息,但现在我还需要一个用非托管代码创建的,可用于替换也包含在 Delphi 项目中的 c-dll。

如果有任何解决我的问题的建议,我将不胜感激。

最好的问候, 弗洛里安

如果有人感兴趣,这里是代码。带有此评论的位置“//这里是我想获取设备编号的地方!!!”是设备号的请求,如果它可以工作的话。

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】:

我发现了我的问题所在。从我在互联网上阅读的内容来看,似乎其他人也遇到了和我一样的问题,所以我将发布我的解决方案。

关键在于,使用 SetupApi 可以为 USB 设备获取明显不同的路径值。所有路径值都可用于获取该设备的句柄,但对于可以使用句柄执行的操作,显然存在差异。 我的失败是使用 GUID_DEVINTERFACE_USB_DEVICE 列出设备。我发现当我使用 GUID_DEVINTERFACE_DISK 时,我得到一个不同的路径值,让我请求设备号。这样我就可以获得驱动器号的链接。 使用 GUID_DEVINTERFACE_DISK 获得的路径值还包含序列号,但不包含供应商和产品 ID。但是由于两个路径值都包含序列,因此获取它们并建立关系是没有问题的。

我用 Windows XP、7 和 8 测试了代码,它运行良好。只有上面代码示例的 FileCreate 代码必须调整(将 GENERIC_WRITE 替换为 0)。否则需要管理员权限或兼容模式。

我并没有试图找出这些不同的 GUID 值真正代表什么。在这方面有更深入了解的人可能会提供更好的解释。

最好的问候, 弗洛里安

【讨论】:

想必USB设备也是磁盘设备的父设备,所以也可以这样链接。

以上是关于通过设备路径或句柄获取 U 盘盘符的主要内容,如果未能解决你的问题,请参考以下文章

如何改系统启动的盘符

Windows如何自定义U盘盘符文件夹图标文件夹背景

移动硬盘文件或目录损坏且无法读取怎么修复

使用C#获取盘符

06Shell并发控制

通过索引获取(真实)监视器的句柄