如何从命令行获取Windows系统USB设备的准确电源状态?
USB设备电源状态不一致问题与命令行获取方案
状态差异原因
设备管理器与USBView的状态差异源于两者监控的设备对象层级不同:
- 设备管理器显示的是**功能设备对象(FDO)**的电源状态,对应设备功能驱动栈的顶层,反映设备的功能层面工作状态。
- USBView显示的是**USB总线驱动的物理设备对象(PDO)**的电源状态,对应总线层面的设备对象,USB总线驱动可能在设备空闲时将PDO切换到D2,而上层FDO仍保持D0,导致状态矛盾。
要获取Windows视角的准确状态,需明确目标是FDO还是PDO的状态,以下是几种命令行/代码实现方案:
方案一:PowerShell脚本(无需管理员权限,获取FDO状态)
1. 枚举所有USB设备的电源状态
Get-PnpDevice -Class USB | Where-Object { $_.Status -eq "OK" } | ForEach-Object { $powerStateProp = Get-PnpDeviceProperty -InstanceId $_.InstanceId -KeyName DEVPKEY_Device_PowerState [PSCustomObject]@{ 设备名称 = $_.FriendlyName 实例ID = $_.InstanceId 电源状态 = switch ($powerStateProp.Data) { 0 { "D0 (工作状态)" } 1 { "D1 (中间休眠)" } 2 { "D2 (中间休眠)" } 3 { "D3 (深度休眠)" } default { "未知状态" } } } } | Format-Table -AutoSize
2. 按VID:PID查询单个设备
# 替换为目标设备的VID和PID(十六进制字符串,无需0x前缀) $targetVid = "1234" $targetPid = "5678" Get-PnpDevice -Class USB | Where-Object { $_.InstanceId -match "VID_$targetVid&PID_$targetPid" } | ForEach-Object { $powerStateProp = Get-PnpDeviceProperty -InstanceId $_.InstanceId -KeyName DEVPKEY_Device_PowerState [PSCustomObject]@{ 设备名称 = $_.FriendlyName VID_PID = "VID_$targetVid&PID_$targetPid" 电源状态 = switch ($powerStateProp.Data) { 0 { "D0 (工作状态)" } 1 { "D1 (中间休眠)" } 2 { "D2 (中间休眠)" } 3 { "D3 (深度休眠)" } default { "未知状态" } } } } | Format-List
方案二:C/C++程序(需管理员权限,获取PDO/FDO状态)
以下程序可直接枚举USB设备的PDO,获取与USBView一致的电源状态,支持枚举所有设备或按VID:PID查询:
#include <windows.h> #include <setupapi.h> #include <initguid.h> #include <devpkey.h> #include <iostream> #include <vector> #include <string> #pragma comment(lib, "setupapi.lib") const char* PowerStateToString(DWORD state) { switch (state) { case 0: return "D0 (工作状态)"; case 1: return "D1 (中间休眠)"; case 2: return "D2 (中间休眠)"; case 3: return "D3 (深度休眠)"; default: return "未知状态"; } } void EnumerateAllUSBDevices() { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) { std::cerr << "SetupDiGetClassDevs 失败,错误码: " << GetLastError() << std::endl; return; } SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) { DWORD requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); std::vector<BYTE> detailData(requiredSize); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailData.data()); pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devInfoData = {0}; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) { std::cerr << "SetupDiGetDeviceInterfaceDetail 失败,错误码: " << GetLastError() << std::endl; continue; } WCHAR friendlyName[256] = {0}; SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(friendlyName), sizeof(friendlyName), NULL); DWORD powerState = 0; DEVPROPTYPE propType; if (SetupDiGetDeviceProperty(hDevInfo, &devInfoData, &DEVPKEY_Device_PowerState, &propType, reinterpret_cast<PBYTE>(&powerState), sizeof(powerState), NULL, 0)) { std::wcout << L"设备名称: " << friendlyName << std::endl; std::wcout << L"设备路径: " << pDetailData->DevicePath << std::endl; std::cout << "电源状态: " << PowerStateToString(powerState) << std::endl; std::cout << "-------------------------" << std::endl; } else { std::cerr << "SetupDiGetDeviceProperty 失败,错误码: " << GetLastError() << std::endl; } } SetupDiDestroyDeviceInfoList(hDevInfo); } void QueryUSBDeviceByVidPid(const std::wstring& vid, const std::wstring& pid) { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) { std::cerr << "SetupDiGetClassDevs 失败,错误码: " << GetLastError() << std::endl; return; } SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); bool found = false; for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) { DWORD requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); std::vector<BYTE> detailData(requiredSize); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailData.data()); pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA devInfoData = {0}; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) { std::cerr << "SetupDiGetDeviceInterfaceDetail 失败,错误码: " << GetLastError() << std::endl; continue; } WCHAR hardwareId[256] = {0}; SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_HARDWAREID, NULL, reinterpret_cast<PBYTE>(hardwareId), sizeof(hardwareId), NULL); std::wstring hwId(hardwareId); std::wstring targetId = L"USB\\VID_" + vid + L"&PID_" + pid; if (hwId.find(targetId) != std::wstring::npos) { WCHAR friendlyName[256] = {0}; SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(friendlyName), sizeof(friendlyName), NULL); DWORD powerState = 0; DEVPROPTYPE propType; if (SetupDiGetDeviceProperty(hDevInfo, &devInfoData, &DEVPKEY_Device_PowerState, &propType, reinterpret_cast<PBYTE>(&powerState), sizeof(powerState), NULL, 0)) { std::wcout << L"找到目标设备:" << std::endl; std::wcout << L"设备名称: " << friendlyName << std::endl; std::wcout << L"硬件ID: " << hardwareId << std::endl; std::cout << "电源状态: " << PowerStateToString(powerState) << std::endl; found = true; break; } else { std::cerr << "SetupDiGetDeviceProperty 失败,错误码: " << GetLastError() << std::endl; } } } if (!found) { std::wcout << L"未找到VID:" << vid << L" PID:" << pid << L"的USB设备" << std::endl; } SetupDiDestroyDeviceInfoList(hDevInfo); } int wmain(int argc, wchar_t* argv[]) { if (argc == 1) { std::cout << "枚举所有USB设备电源状态:" << std::endl; std::cout << "-------------------------" << std::endl; EnumerateAllUSBDevices(); } else if (argc == 3) { QueryUSBDeviceByVidPid(argv[1], argv[2]); } else { std::wcout << L"用法:" << std::endl; std::wcout << L" USBPowerStatus.exe - 枚举所有USB设备电源状态" << std::endl; std::wcout << L" USBPowerStatus.exe <VID> <PID> - 查询指定VID:PID的设备电源状态" << std::endl; std::wcout << L"示例: USBPowerStatus.exe 1234 5678" << std::endl; return 1; } return 0; }
编译与运行
- 用MSVC编译:
cl USBPowerStatus.cpp /link setupapi.lib - 需以管理员权限运行程序,否则无法访问部分设备的电源状态信息
内容的提问来源于stack exchange,提问作者sdbbs
相关产品推荐
相关产品推荐

