【问题标题】:How to find all connected removable USB storage devices in Windows?如何在 Windows 中查找所有已连接的可移动 USB 存储设备?
【发布时间】:2017-12-13 10:12:04
【问题描述】:

我正在编写一个处理 USB 驱动器的程序,为了获取有关连接新设备的信息,我注册了一个窗口消息 WM_DEVICECHANGE。但是,我当然不会收到有关在我的程序启动之前连接的设备的消息。为了处理这样的设备,我写了一个搜索功能,但我得到了一个奇怪的结果。它找到我的闪存驱动器,但不认为它是可移动的。为什么? 功能

bool FindConnectedRemovableUsbstorDevices(std::list<std::wstring>& UsbList)
{
    std::wstring ClassGuidString(L"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}");
    GUID ClassGuid;
    BYTE buf[1024];
    PSP_DEVICE_INTERFACE_DETAIL_DATA_W pspdidd =         reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buf);
    SP_DEVICE_INTERFACE_DATA spdid;
    SP_DEVINFO_DATA spdd;
    DWORD size;
    SP_DEVINFO_DATA dev_data;
    DWORD properties;


    if(NOERROR != CLSIDFromString(ClassGuidString.c_str(), &ClassGuid))
        return false;

    HDEVINFO dev_info = INVALID_HANDLE_VALUE;
    dev_info = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

    if (dev_info == INVALID_HANDLE_VALUE)
        return false;

    DWORD index = 0;
    BOOL ret = FALSE;

    spdid.cbSize = sizeof(spdid);

    while (true)
    {
        ret = SetupDiEnumDeviceInterfaces(dev_info, NULL, &ClassGuid, index, &spdid);
    if (!ret)
        break;

    size = 0;
    SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, NULL, 0, &size, NULL);
    //Get required size

    if (size == 0 || size >= sizeof(buf))
        continue;
    //prepare structs
    ZeroMemory(reinterpret_cast<PVOID>(pspdidd), 1024);
    pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!

    ZeroMemory(reinterpret_cast<PVOID>(&spdd), sizeof(spdd));
    spdd.cbSize = sizeof(spdd);

    BOOL res = SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, pspdidd, size, &size, &spdd);
    //Get info
    if (!res)
        continue;

    HANDLE drive = CreateFileW(pspdidd->DevicePath, FILE_READ_ATTRIBUTES,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, 0, NULL);//open device
    if (drive == INVALID_HANDLE_VALUE)
        continue;

    printf("\n%S\r\n", pspdidd->DevicePath);

    DWORD bytes_returned = 0;
    BOOL b = DeviceIoControl(drive, IOCTL_STORAGE_CHECK_VERIFY2, NULL, 0, NULL, 0, &bytes_returned, NULL);
    if (!b) //check is card reader?
    {
        printf("IOCTL_STORAGE_CHECK_VERIFY2 error = %d\r\n", GetLastError());
        goto stop_process_device;
    }

    bytes_returned = 0;
    STORAGE_DEVICE_NUMBER sdn;
    //Get Drive number
    b = DeviceIoControl(drive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &bytes_returned, NULL);
    if (!b)
        goto stop_process_device;
    RtlZeroMemory(&dev_data, sizeof(SP_DEVINFO_DATA));
    dev_data.cbSize = sizeof(dev_data);
    if (SetupDiEnumDeviceInfo(dev_info, sdn.DeviceNumber, &dev_data))
    {
        //check property
        b = SetupDiGetDeviceRegistryProperty(dev_info, &dev_data, SPDRP_REMOVAL_POLICY, NULL, 
            reinterpret_cast<PBYTE>(&properties), sizeof(properties), NULL);
        if (b && properties != CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL)
        {
            UsbList.push_back(pspdidd->DevicePath);
            printf("REMOVAL\r\n");
        }
    }
stop_process_device:
        CloseHandle(drive);
        index++;
    }
    SetupDiDestroyDeviceInfoList(dev_info);
    return true;
}

然后输出

\\?\usbstor#disk&ven_generic-&prod_ms#ms-pro#hg&rev_1.00#20090703819900000&1#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
IOCTL_STORAGE_CHECK_VERIFY2 error = 21 
\\?\ide#diskst3500418as_____________________________cc38____#5&5c6cfd6&0&1.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
REMOVAL 
\\?\usbstor#disk&ven_generic-&prod_sd#mmc&rev_1.00#20090703819900000&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
IOCTL_STORAGE_CHECK_VERIFY2 error = 21 
\\?\scsi#disk&ven_ocz&prod_revodrive3_x2#5&19ad1f72&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
\\?\ide#diskst1000lm014-1ej164______________________sm30____#5&2ea7e938&0&0.1.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
\\?\usbstor#disk&ven_sandisk&prod_extreme&rev_0001#aa010823150434152862&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
\\?\ide#diskwdc_wd1002fbys-02a6b0___________________03.00c06#5&2ea7e938&0&0.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} 
REMOVAL

错误 21 是读卡器空。 闪迪是我的闪存。在 Debug 中我看到 SetupDiGetDeviceRegistryProperty 返回属性 CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL,但我真的不知道为什么......

【问题讨论】:

  • GetDriveType() 为这个驱动器返回什么?
  • GetDriveType 等待名称中的尾随反斜杠,因此不会直接使用此类路径。但是它没有什么特别的 - 按名称打开文件并使用ZwQueryVolumeInformationFile 查询FileFsDeviceInformation。并根据FILE_FS_DEVICE_INFORMATION.DeviceType 返回——这实际上与删除检测几乎无关。可能更好地将IOCTL_STORAGE_QUERY_PROPERTYStorageDeviceProperty 一起使用并寻找STORAGE_DEVICE_DESCRIPTOR.RemovableMedia 字段
  • zett42 - GetDriveType 为我的设备名称返回 1 (DRIVE_NO_ROOT_DIR)。
  • @RbMm 你是对的!太棒了!
  • returns 1 (DRIVE_NO_ROOT_DIR) 这是因为 - 尾随反斜杠是必需的。 您需要在调用 GetDriveType 之前将 / 附加到末尾。但你可以自己打电话给CreateFileW 而不是ZwQueryVolumeInformationFile(..FileFsDeviceInformation)。并在Characteristics 中查找FILE_REMOVABLE_MEDIA。在现代操作系统版本中(但在 xp 中不存在)也存在 FILE_PORTABLE_DEVICE 标志

标签: c++ windows winapi setupapi


【解决方案1】:

如果您只想找到已连接的可移动设备,还有一个更简单的选择,使用 GetLogicalDriveStrings()GetDriveType()

#define MAX_DRIVES 256

bool FindConnectedRemovableUsbstorDevices(std::list<std::wstring>& UsbList)
{
    wchar_t  drives[MAX_DRIVES];
    wchar_t* temp = drives;

    if (GetLogicalDriveStringsW(MAX_DRIVES, drives) == 0)
        return false;

    while (*temp != NULL)
    {
        if (GetDriveTypeW(temp) == 2 /* DRIVE_REMOVABLE */)
            UsbList.push_back(temp);

        // Go to the next drive
        temp += lstrlenW(temp) + 1;
    }

    return true;
}

【讨论】:

  • 我知道这种方式,但我的程序也必须与未安装的设备一起使用..
【解决方案2】:

我不知道为什么我的第一种检测可移动媒体的方法如此奇怪,但 RbMm 方法效果很好。我使用IOCTL_STORAGE_QUERY_PROPERTYStorageDeviceProperty 向每个找到的设备发送IOCTL 查询,并查找STORAGE_DEVICE_DESCRIPTOR.RemovableMedia 字段。我的所有设备都已成功正确识别。

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多