Windows复位USB集线器HUB端口设备RestartUsbPort
2024-02-06
290
1
本人描述了如何在 Windows 下使用IOCTL_USB_HUB_CYCLE_PORT 重新启动USB端口。具体过程为:通过给定的设备实例ID在 Windows设备管理中查找USB 备、确定使用的 USB 端口号、获取其父设备(其 USB 集线器)、打开集线器并执行 IOCTL_USB_HUB_CYCLE_PORT 调用。
RestartUsbPort工具下载地址:https://www.usbzh.com/article/detail-1192.html
介绍
有时,USB 设备会停止按预期工作,重新插入它们会有所帮助。通过代码执行重新插入可能会很方便。
如果您想尝试重新启动 USB 端口是否有帮助,可以尝试使用UsbTreeView或RestartUsbPort工具来实现。
在Windows系统下,IOCTL_USB_HUB_CYCLE_PORT会重新启动 USB 端口,从而启动所连接设备的重新枚举。
- 该功能在 XP 下可用,但通常仅适用于运行 Microsoft 标准驱动程序的集线器驱动。第三方驱动通常会返回ERROR_UNKNOWN_FUNCTION。
- 在 Vista 和 Windows 7 下,Windows 标准驱动程序不再支持它,它总是失败并显示ERROR_NOT_SUPPORTED.
- 从 Windows 8 开始,它再次可用,但与 XP 相比,需要管理员权限。如果没有管理员权限,它会像在 Vista 和 Win7 下一样失败,ERROR_NOT_SUPPORTED或者从 Win10 版本 1903 开始ERROR_GEN_FAILURE失败,这两种情况在这里都是相当误导的,因为这是一个权限问题。
代码实现
现将所有内容放在一个函数中,该函数使用USB设备的设备实例ID作为唯一参数。
bool CycleUsbDevice(char* pszUsbDeviceId)
{
// Step 1: find the USB device in the device manager
DEVINST DevInst = 0;
if ( CR_SUCCESS != CM_Locate_DevNode(&DevInst, pszUsbDeviceId, 0) ) {
return false; //----
}
// Step 2: Determine the USB port number.
// Since Vista it can be read reliably from the device location info:
char szLocation[64] = "";
DWORD dwType = 0;
ULONG uLen = sizeof(szLocation);
if ( CR_SUCCESS != CM_Get_DevNode_Registry_Property
(DevInst, CM_DRP_LOCATION_INFORMATION, &dwType, szLocation, &uLen, 0) ) {
return false; //----
}
// 0123456789
// must be like "Port_#0004.Hub_#0014"
if ( 0 != strncmp(szLocation, "Port_#", 6) ) {
return false; //----
}
int PortNumber = atoi(szLocation + 6); // leading zeros are ok with atoi
// Step 3: the USB hub is the parent device
DEVINST DevInstHub = 0;
if ( CR_SUCCESS != CM_Get_Parent(&DevInstHub, DevInst, 0) ) {
return false; //----
}
// Step 4: scan all USB hubs for this DEVINST to get its DevicePath
// which we need to open the hub
char szHubDevPath[MAX_PATH] = "";
const GUID* DevIfGuid = &GUID_DEVINTERFACE_USB_HUB;
HDEVINFO hDevInfo = SetupDiGetClassDevs
(DevIfGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if ( INVALID_HANDLE_VALUE == hDevInfo ) {
return false; //----
}
char DataBuf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevIfDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)DataBuf;
SP_DEVICE_INTERFACE_DATA DevIfData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
SP_DEVINFO_DATA DevInfoData = { sizeof(SP_DEVINFO_DATA) };
DWORD dwSize;
for ( DWORD dwIndex = 0; SetupDiEnumDeviceInterfaces
(hDevInfo, NULL, DevIfGuid, dwIndex, &DevIfData); dwIndex++ ) {
pDevIfDetailData->cbSize =
sizeof(*pDevIfDetailData); // yes, 5 (or 6 if UNICODE)
dwSize = sizeof(DataBuf);
if ( SetupDiGetDeviceInterfaceDetail(hDevInfo,
&DevIfData, pDevIfDetailData, dwSize, &dwSize, &DevInfoData) ) {
if ( DevInfoData.DevInst == DevInstHub ) {
// hub found, keep its DevicePath
strcpy(szHubDevPath, pDevIfDetailData->DevicePath);
break;
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
if ( ! szHubDevPath[0] ) {
return false; //----
}
// Step 5: open the hub
HANDLE hHub = CreateFile(szHubDevPath, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if ( INVALID_HANDLE_VALUE == hHub ) {
return false; //----
}
// Step 6: call IOCTL_USB_HUB_CYCLE_PORT
typedef struct _USB_CYCLE_PORT_PARAMS {
ULONG ConnectionIndex;
ULONG StatusReturned;
} USB_CYCLE_PORT_PARAMS, *PUSB_CYCLE_PORT_PARAMS;
USB_CYCLE_PORT_PARAMS CyclePortParams = { PortNumber, 0 }; // in and out
DWORD dwBytes;
int res = DeviceIoControl(hHub, IOCTL_USB_HUB_CYCLE_PORT,
&CyclePortParams, sizeof(CyclePortParams),
&CyclePortParams, sizeof(CyclePortParams),
&dwBytes, NULL);
CloseHandle(hHub);
return ( (0 != res) && (0 == CyclePortParams.StatusReturned) );
}
说明
- 微软官方方档说明使用IOCTL_USB_HUB_CYCLE_PORT的函数DeviceIoControl的Output Buffer应为NULL ,但实际也是有的。
- 重启的设备必须安装了USB驱动程序并且与设备必须存在。否则会出现错误 433 ( ERROR_NO_SUCH_DEVICE) 或自 Windows 10 21H2 起出现错误 50 ( ERROR_NOT_SUPPORTED)。Win11又返回的是 1167 ( ERROR_DEVICE_NOT_CONNECTED)。
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936