【发布时间】:2018-02-28 09:16:09
【问题描述】:
我的环境:
Qt 5.3.1
Windows 10
我需要找到挂载的 USB 存储设备的路径。
通过路径,我可以通过 Qt 复制文件。
我知道有一个跨平台的libusb。但想知道任何简单的解决方案。
【问题讨论】:
我的环境:
Qt 5.3.1
Windows 10
我需要找到挂载的 USB 存储设备的路径。
通过路径,我可以通过 Qt 复制文件。
我知道有一个跨平台的libusb。但想知道任何简单的解决方案。
【问题讨论】:
首先您需要获得可移动驱动器:
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;
}
}
【讨论】:
首先我们需要枚举所有支持接口GUID_DEVINTERFACE_DISK的设备。然后我们可以在这个界面上打开文件并查询STORAGE_ADAPTER_DESCRIPTOR或STORAGE_DEVICE_DESCRIPTOR并查找
总线类型
指定
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;
}
【讨论】: