Win32API:运行线程后如何检测USB转COM6手持扫描器是否断开?
解决USB转COM扫描器插拔状态监控问题
针对扫描器运行后无法通过WM_DEVICECHANGE的DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE消息检测状态的问题,可采用以下几种方案:
方案一:定期检测COM端口可用性
直接尝试打开目标COM端口,通过返回结果判断设备是否在线。这种方式简单直接,不受WM_DEVICECHANGE消息异常的影响。
示例代码:
BOOL IsComPortOnline(LPCSTR portName) { HANDLE hCom = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hCom != INVALID_HANDLE_VALUE) { CloseHandle(hCom); return TRUE; } DWORD err = GetLastError(); // 区分端口不存在/无法打开与其他错误 return !(err == ERROR_FILE_NOT_FOUND || err == ERROR_ACCESS_DENIED); }
可以启动一个低优先级的定时线程(比如每隔1-2秒),调用该函数并对比上次检测结果,当状态变化时触发在线/离线逻辑。
方案二:基于USB硬件ID枚举设备
USB转COM设备有唯一的VID/PID标识,可通过枚举USB设备并匹配目标硬件ID来判断扫描器是否存在。结合DBT_DEVNODES_CHANGED消息,每次收到该消息时重新枚举即可。
示例代码:
#include <SetupAPI.h> #include <initguid.h> DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); BOOL IsUsbScannerPresent(LPCSTR targetHardwareId) { HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) return FALSE; 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); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredSize); 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)) { CHAR hardwareId[256]; if (SetupDiGetDeviceRegistryPropertyA(hDevInfo, &devInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)hardwareId, sizeof(hardwareId), NULL)) { if (strstr(hardwareId, targetHardwareId) != NULL) { LocalFree(pDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return TRUE; } } } LocalFree(pDetailData); } SetupDiDestroyDeviceInfoList(hDevInfo); return FALSE; }
使用时,将targetHardwareId替换为扫描器的硬件ID(比如USB\VID_1234&PID_5678),在收到DBT_DEVNODES_CHANGED消息时调用该函数,即可判断设备是否被拔出。
方案三:监听已打开串口的读写错误
如果扫描器运行时已打开COM6端口,可在读写操作中检测错误码来判断设备状态。当USB设备被拔出时,串口读写通常会返回ERROR_IO_DEVICE或ERROR_GEN_FAILURE这类错误。
示例逻辑:
BOOL ReadScannerData(HANDLE hCom, LPBYTE buf, DWORD bufSize, LPDWORD bytesRead) { if (!ReadFile(hCom, buf, bufSize, bytesRead, NULL)) { DWORD err = GetLastError(); if (err == ERROR_IO_DEVICE || err == ERROR_GEN_FAILURE) { // 设备已拔出,标记离线 return FALSE; } // 其他错误,可根据情况处理 } return TRUE; }
在扫描器的读写线程中加入此类错误判断,一旦触发就执行离线处理逻辑。
内容的提问来源于stack exchange,提问作者M. Alexander
相关产品推荐
相关产品推荐

