在C ++中查找当前连接的USB存储路径

问题描述 投票:1回答:2

我的环境:

Qt 5.3.1
Windows 10

我需要找到已安装的USB存储设备的路径。通过该路径,我可以通过Qt复制文件。我知道有一个跨平台的libusb。但想知道任何简单的解决方案。

windows qt winapi mingw
2个回答
1
投票

首先,您需要获得可移动驱动器:

void EnumUsbDrives() {
    DWORD drv = ::GetLogicalDrives();
    if (drv == 0) return;

    DWORD mask = 1;
    TCHAR szDrive[] = _TEXT("?:\\");

    for (uint_t i = 0; i < ('Z' - 'A' + 1); i++, mask <<= 1) {
        if (drv & mask) {
            szDrive[0] = (TCHAR)(_T('A') + i);
            if (::GetDriveType(szDrive) == DRIVE_REMOVABLE) {
                bool bUSB = IsDriveUSB(szDrive);
                if (bUSB) {
                    // Time do to something useful
                }
            }
        }
    }
}

功能IsDriveUSB有点复杂。我是从内部图书馆撕下来的;该函数使用自定义帮助程序类xregistry和xstring_nocase。他们的目的很明显,我相信你可以用其他类似的类或API调用替换它。

bool IsDriveUSB (LPCTSTR szDrive) throw() {
    TCHAR szLogicalDrive[] = _TEXT("\\\\.\\x:");
    szLogicalDrive[4] = szDrive[0];
    HANDLE hDrive = ::CreateFile(szLogicalDrive, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if (hDrive == INVALID_HANDLE_VALUE) return false;       // Can't open drive so we have to assume the drive is fixed

    VOLUME_DISK_EXTENTS vde;
    DWORD dwBytesReturned = 0;
    BOOL br = ::DeviceIoControl(hDrive, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &vde, sizeof(vde), &dwBytesReturned, NULL);
    ::CloseHandle(hDrive);
    if (!br) return false;      // Can't get extents info so we have to assume the drive is fixed

    if (vde.NumberOfDiskExtents != 1) return false;
    ULONG uPhysDrive = vde.Extents[0].DiskNumber;
    TCHAR szPhysDrive[16];
    _stprintf(szPhysDrive, _TEXT("%u"), uPhysDrive);

    try {
        xregistry rk(HKEY_LOCAL_MACHINE, OS.Is64bit());
        rk.open(_TEXT("SYSTEM\\CurrentControlSet\\services\\Disk\\Enum"), KEY_QUERY_VALUE);
        if (!rk.value_exists(szPhysDrive)) return false;
        xstring_nocase strInterface = rk.get_string(szPhysDrive).substring(0, 7);
        return strInterface == _TEXT("USBSTOR");
    }
    catch (...) {
        return false;
    }
}

0
投票

首先,我们需要枚举所有支持接口GUID_DEVINTERFACE_DISK的设备。然后我们可以在这个界面上打开文件并查询它STORAGE_ADAPTER_DESCRIPTORSTORAGE_DEVICE_DESCRIPTOR并寻找

BusType

指定STORAGE_BUS_TYPE类型的值,该值指示设备所连接的总线的类型。

对于USB,这将是BusTypeUsb

static volatile UCHAR guz;

CONFIGRET EnumUsbStor()
{
    CONFIGRET err;

    PVOID stack = alloca(guz);
    ULONG BufferLen = 0, NeedLen = 256;

    union {
        PVOID buf;
        PWSTR pszDeviceInterface;
    };

    for(;;) 
    {
        if (BufferLen < NeedLen)
        {
            BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
        }

        switch (err = CM_Get_Device_Interface_ListW(const_cast<PGUID>(&GUID_DEVINTERFACE_DISK), 
            0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
        {
        case CR_BUFFER_SMALL:
            if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, const_cast<PGUID>(&GUID_DEVINTERFACE_DISK), 
                0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
            {
        default:
            return err;
            }
            continue;

        case CR_SUCCESS:

            while (*pszDeviceInterface)
            {
                BOOLEAN bIsUsb = FALSE;
                HANDLE hFile = CreateFile(pszDeviceInterface, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

                if (hFile != INVALID_HANDLE_VALUE)
                {
                    STORAGE_PROPERTY_QUERY spq = { StorageAdapterProperty, PropertyStandardQuery }; 
                    STORAGE_ADAPTER_DESCRIPTOR sad;

                    ULONG n;
                    if (DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), &sad, sizeof(sad), &n, 0))
                    {
                        bIsUsb = sad.BusType == BusTypeUsb;
                    }
                    CloseHandle(hFile);
                }

                pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
            }
            return 0;
        }
    }
}

我们也可以在接口字符串中查找EnumeratorName - 这是USBSTOR。快速结束简单:

wcsstr(_wcsupr(pszDeviceInterface), L"\\USBSTOR#");

在接口名称中搜索\USBSTOR#子字符串。或更正确 - 从接口名称获取Device_InstanceId并查询DEVPKEY_Device_EnumeratorName

CONFIGRET IsUsbStor(DEVINST dnDevInst, BOOLEAN& bUsbStor)
{
    ULONG cb = 0, rcb = 256;

    PVOID stack = alloca(guz);
    DEVPROPTYPE PropertyType;

    CONFIGRET status;

    union {
        PVOID pv;
        PWSTR EnumeratorName;
        PBYTE pb;
    };

    do 
    {
        if (cb < rcb)
        {
            rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
        }

        status = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_EnumeratorName, &PropertyType,
            pb, &rcb, 0);

        if (status == CR_SUCCESS)
        {
            if (PropertyType == DEVPROP_TYPE_STRING)
            {
                DbgPrint("EnumeratorName = %S\n", EnumeratorName);
                bUsbStor = !_wcsicmp(L"USBSTOR", EnumeratorName);
            }
            else
            {
                status = CR_WRONG_TYPE;
            }

            break;
        }

    } while (status == CR_BUFFER_SMALL);

    return status;
}

CONFIGRET IsUsbStor(PCWSTR pszDeviceInterface, BOOLEAN& bUsbStor)
{
    ULONG cb = 0, rcb = 256;

    PVOID stack = alloca(guz);
    DEVPROPTYPE PropertyType;

    CONFIGRET status;

    union {
        PVOID pv;
        PWSTR DeviceID;
        PBYTE pb;
    };

    do 
    {
        if (cb < rcb)
        {
            rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
        }

        status = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0);

        if (status == CR_SUCCESS)
        {
            if (PropertyType == DEVPROP_TYPE_STRING)
            {
                DbgPrint("DeviceID = %S\n", DeviceID);

                DEVINST dnDevInst;

                status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);

                if (status == CR_SUCCESS)
                {
                    status = IsUsbStor(dnDevInst, bUsbStor);
                }
            }
            else
            {
                status = CR_WRONG_TYPE;
            }

            break;
        }

    } while (status == CR_BUFFER_SMALL);

    return status;
}
© www.soinside.com 2019 - 2024. All rights reserved.