You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:00:02