如何通过Windows API检测USB移动设备并获取友好设备信息?
检测Windows上的USB存储设备(含移动智能设备)
需求
检测所有连接到Windows的USB存储设备,包括智能手机这类移动设备。
现有尝试分析
1. 基于磁盘设备接口(GUID_DEVINTERFACE_DISK)
此方法可检测硬盘和U盘,但无法识别USB连接的移动设备。
代码示例:
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE | DIGCF_PROFILE); SP_DEVINFO_DATA deviceInfoData; deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (DWORD dwDeviceIndex = 0; SetupDiEnumDeviceInfo(deviceInfoSet, dwDeviceIndex, &deviceInfoData); dwDeviceIndex++) { DEVINST hDevInst = deviceInfoData.DevInst; DEVINST hParentDevInst; CONFIGRET cRet = CM_Get_Parent(&hParentDevInst, hDevInst, 0); TCHAR wsParentDeviceID[MAX_DEVICE_ID_LEN]; cRet = CM_Get_Device_ID(hParentDevInst, wsParentDeviceID, sizeof(wsParentDeviceID) / sizeof(TCHAR), 0); TCHAR wsDeviceID[MAX_DEVICE_ID_LEN]; cRet = CM_Get_Device_ID(hDevInst, wsDeviceID, sizeof(wsDeviceID) / sizeof(TCHAR), 0); // Get device friendly name DEVPROPTYPE propertyType; WCHAR deviceName[MAX_PATH]; DWORD bufferSize = sizeof(deviceName); if (SetupDiGetDeviceProperty(deviceInfoSet, &deviceInfoData, &DEVPKEY_Device_FriendlyName, &propertyType, reinterpret_cast<PBYTE>(deviceName), bufferSize, NULL, 0)) { std::wcout << L"Device friendly name = " << deviceName << std::endl; } else { std::wcout << L"No device friendly name detected\n"; } // Get manufacturer WCHAR manufacturer[MAX_PATH]; bufferSize = sizeof(manufacturer); if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG, NULL, reinterpret_cast<PBYTE>(manufacturer), bufferSize, NULL)) { std::wcout << L"Device manufacturer = " << manufacturer << std::endl; } else { std::wcout << L"No device manufacturer detected\n"; } } if (deviceInfoSet) { SetupDiDestroyDeviceInfoList(deviceInfoSet); }
输出示例:
Device friendly name = VendorCo ProductCode USB Device Device manufacturer = (Standard disk drives) DeviceId = USBSTOR\DISK&VEN_VENDORCO&PROD_PRODUCTCODE&REV_2.00\3755241199071418340&0 Parent DeviceId = USB\VID_FFFF&PID_5678\3755241199071418340 Device friendly name = VBOX HARDDISK Device manufacturer = (Standard disk drives) DeviceId = SCSI\DISK&VEN_VBOX&PROD_HARDDISK\4&2621AEAE&0&000000 Parent DeviceId = PCI\VEN_8086&DEV_2829&SUBSYS_00000000&REV_02\3&267A616A&0&68
2. 基于通用USB设备接口(GUID_DEVINTERFACE_USB_DEVICE)
此方法可检测移动设备,但获取的信息不够友好,无法获取Windows显示的设备型号名称。
代码片段:
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
输出示例:
No device friendly name detected Device manufacturer = Huawei DeviceId = USB\VID_2717&PID_FF40\D323C6439871 Parent DeviceId = USB\ROOT_HUB30\4&24054718&0&0 No device friendly name detected Device manufacturer = (Standard system devices) DeviceId = USB\VID_80EE&PID_0021\5&12C8F4C0&0&1 Parent DeviceId = USB\ROOT_HUB30\4&24054718&0&0 No device friendly name detected Device manufacturer = Compatible USB storage device DeviceId = USB\VID_FFFF&PID_5678\3755241199071418340 Parent DeviceId = USB\ROOT_HUB30\4&24054718&0&0
3. 基于Windows便携设备类(GUID_DEVCLASS_WPD)
此方法可检测外接硬盘、U盘及安卓手机,能获取厂商信息和多数设备的友好名称,但部分手机无友好名称,且无法获取所有设备的型号信息。
代码片段:
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_WPD, NULL, NULL, DIGCF_PRESENT);
解决方案:结合WPD API与设备属性查询
核心思路
使用Windows Portable Devices (WPD) API直接枚举便携设备,该API专为移动设备设计,可直接获取设备的友好名称、厂商、型号等信息;同时可结合SetupDi系列API补充存储设备的信息,实现完整的USB存储设备(含移动设备)检测。
代码示例:使用WPD API获取设备详细信息
#include <PortableDeviceApi.h> #include <PortableDevice.h> #include <iostream> #include <vector> #pragma comment(lib, "PortableDeviceGUIDs.lib") #pragma comment(lib, "PortableDevice.lib") void EnumerateWPDDevices() { HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { std::wcerr << L"CoInitialize failed: 0x" << std::hex << hr << std::endl; return; } IPortableDeviceManager* pDeviceManager = nullptr; hr = CoCreateInstance(CLSID_PortableDeviceManager, NULL, CLSCTX_INPROC_SERVER, IID_IPortableDeviceManager, (VOID**)&pDeviceManager); if (FAILED(hr)) { std::wcerr << L"CoCreateInstance(PortableDeviceManager) failed: 0x" << std::hex << hr << std::endl; CoUninitialize(); return; } // 获取设备数量 DWORD deviceCount = 0; hr = pDeviceManager->GetDevices(NULL, &deviceCount); if (FAILED(hr) || deviceCount == 0) { std::wcout << L"No WPD devices detected." << std::endl; pDeviceManager->Release(); CoUninitialize(); return; } // 分配内存存储设备ID std::vector<PWSTR> deviceIDs(deviceCount); hr = pDeviceManager->GetDevices(deviceIDs.data(), &deviceCount); if (FAILED(hr)) { std::wcerr << L"GetDevices failed: 0x" << std::hex << hr << std::endl; pDeviceManager->Release(); CoUninitialize(); return; } // 遍历每个设备,获取详细信息 for (DWORD i = 0; i < deviceCount; i++) { PWSTR deviceID = deviceIDs[i]; std::wcout << L"=== Device " << (i+1) << L" ===" << std::endl; std::wcout << L"Device ID: " << deviceID << std::endl; // 获取友好名称 WCHAR friendlyName[MAX_PATH] = {0}; DWORD nameSize = ARRAYSIZE(friendlyName); hr = pDeviceManager->GetDeviceFriendlyName(deviceID, friendlyName, &nameSize); std::wcout << L"Friendly Name: " << (SUCCEEDED(hr) && friendlyName[0] ? friendlyName : L"Unknown") << std::endl; // 获取厂商名称 WCHAR manufacturer[MAX_PATH] = {0}; DWORD manuSize = ARRAYSIZE(manufacturer); hr = pDeviceManager->GetDeviceManufacturer(deviceID, manufacturer, &manuSize); std::wcout << L"Manufacturer: " << (SUCCEEDED(hr) && manufacturer[0] ? manufacturer : L"Unknown") << std::endl; // 获取设备型号 WCHAR model[MAX_PATH] = {0}; DWORD modelSize = ARRAYSIZE(model); hr = pDeviceManager->GetDeviceModel(deviceID, model, &modelSize); std::wcout << L"Model: " << (SUCCEEDED(hr) && model[0] ? model : L"Unknown") << std::endl; std::wcout << L"-------------------------" << std::endl; CoTaskMemFree(deviceID); } pDeviceManager->Release(); CoUninitialize(); } int main() { EnumerateWPDDevices(); return 0; }
补充优化
- 区分移动设备与普通存储设备:可通过设备ID中的
VID/PID(USB厂商/产品ID),或检查设备是否同时支持WPD和大容量存储接口,来筛选移动设备。 - 补充缺失信息:若WPD API无法获取某些设备的信息,可使用
SetupDiGetDeviceRegistryProperty查询设备注册表属性,如SPDRP_DEVICEDESC、SPDRP_FRIENDLYNAME等,补充缺失的名称信息。 - 权限注意:确保程序以足够权限运行,避免因权限不足无法读取设备信息。
内容的提问来源于stack exchange,提问作者RobertGG
相关产品推荐
相关产品推荐

