QT外接设备(串口与U盘)等设备热插拔实时检测

引言:在日常串口开发中,串口热插拔的实时检测可以大大提高我们的使用体验,不至于在要添加串口时重启一遍软件,这样显得很不专业。


调用注册事件的类需要继承 QAbstractNativeEventFilter ,这是一个纯虚函数类

重写函数

virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) = 0:

第一步(注册监测设备)

  • 注册事件要小心的点在于注册事件不能写在函数外,所以需要写一个初始化注册函数 registerDevice()调用,在UI初始化时调用即可

接下来就直接上代码:

void MainWindow::registerDevice(){
    
    static const GUID GUID_DEVINTERFACE_LIST[] =
        {
        // GUID_DEVINTERFACE_USB_DEVICE
        { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },     //USB设备的GUID
        // GUID_DEVINTERFACE_DISK
        { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },
        // GUID_DEVINTERFACE_HID,
        { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },
        // GUID_NDIS_LAN_CLASS
        { 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } },
        // GUID_DEVINTERFACE_COMPORT
        { 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },
        // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
        { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
        // GUID_DEVINTERFACE_PARALLEL
        { 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } },
        // GUID_DEVINTERFACE_PARCLASS
        { 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } },
        };
    
        //注册插拔事件
        HDEVNOTIFY hDevNotify;
        DEV_BROADCAST_DEVICEINTERFACE NotifacationFiler;
        ZeroMemory(&NotifacationFiler, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
        NotifacationFiler.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
        NotifacationFiler.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
               
        
        for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST)/sizeof(GUID); i++)  {
                NotifacationFiler.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];
                hDevNotify = RegisterDeviceNotification((HANDLE)this->winId(), &NotifacationFiler, DEVICE_NOTIFY_WINDOW_HANDLE);
                if (!hDevNotify) {
                    qCritical() << QStringLiteral("注册失败!");
                }else{
                    qDebug()<<"注册成功";
                }
            }
    
}  

第二步(重写消息过滤函数)

bool Moveing_target::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType);
    MSG* msg = reinterpret_cast<MSG*>(message);
    int msgType = msg->message;
    if(msgType == WM_DEVICECHANGE)
    {
        qDebug() << "Recv Event " ;
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
        switch(msg->wParam)
        {
            case DBT_DEVICETYPESPECIFIC:
            {
            qDebug() << "DBT_DEVICETYPESPECIFIC " ;
            break;
            }
            case DBT_DEVICEARRIVAL:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
            {
                PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
                if (lpdbv -> dbcv_flags == 0)
                {
                    // 插入U盘,此处可以做你想做的事
                    // lpdbv->dbcv_unitmask 即盘符标志位,1bit,0为A,1为B,10为C,11为D…以此类推
                    QString USBDisk = QString(this->FirstDriveFromMask(lpdbv->dbcv_unitmask));
                    qDebug() << "USB_Arrived and The USBDisk is: "<<USBDisk ;
                    emit signals_Usb_Stick_Insertion(USBDisk);

                }
            }
            qDebug() << "DBT_DEVICEARRIVAL" ;
            break;
            case DBT_DEVICEREMOVECOMPLETE:
            if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
            {
                PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
                if (lpdbv -> dbcv_flags == 0)
                {
                    qDebug() << "USB_delete";
                }
            }
            qDebug() << "DBT_DEVICEREMOVECOMPLETE" ;
            break;
        }
    }
    return false;
   }

   char Moveing_target::FirstDriveFromMask(ULONG unitmask)
   {
    char i;

    for (i = 0; i < 26; ++i)
    {
    if (unitmask & 0x1)
    break;
    unitmask = unitmask >> 1;
    }
    return (i + 'A');
}

然后在把继承的类插入QApplication对象里安装此过滤器即可

a.installNativeEventFilter(&t);

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现串口热插拔检测,可以使用Qt的QSerialPort类和QSerialPortInfo类。 QSerialPort类用于访问串口,可以通过它打开、关闭、设置串口参数、读取和写入串口数据等。而QSerialPortInfo类则提供了有关系统中可用串口的信息,可以用于检测串口热插拔事件。 以下是一个简单的示例代码,演示如何检测串口热插拔事件: ```cpp #include <QtCore> #include <QtSerialPort> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 枚举当前可用的串口 QList<QSerialPortInfo> serialPorts = QSerialPortInfo::availablePorts(); foreach (const QSerialPortInfo &serialPortInfo, serialPorts) { qDebug() << "Found serial port:" << serialPortInfo.portName(); } // 创建一个QSerialPort对象并打开串口 QSerialPort serialPort; serialPort.setPortName("COM1"); serialPort.setBaudRate(QSerialPort::Baud9600); if (serialPort.open(QIODevice::ReadWrite)) { qDebug() << "Opened serial port:" << serialPort.portName(); } else { qDebug() << "Failed to open serial port:" << serialPort.portName(); } // 监听串口热插拔事件 QSerialPortInfo::availablePortsChanged.connect([]() { QList<QSerialPortInfo> currentSerialPorts = QSerialPortInfo::availablePorts(); qDebug() << "Serial ports changed. Found" << currentSerialPorts.count() << "serial ports."; // 遍历当前可用的串口,判断是否有串口被插入或拔出 foreach (const QSerialPortInfo &currentSerialPortInfo, currentSerialPorts) { bool found = false; foreach (const QSerialPortInfo &serialPortInfo, serialPorts) { if (currentSerialPortInfo.portName() == serialPortInfo.portName()) { found = true; break; } } if (!found) { qDebug() << "Serial port" << currentSerialPortInfo.portName() << "was inserted."; } } foreach (const QSerialPortInfo &serialPortInfo, serialPorts) { bool found = false; foreach (const QSerialPortInfo &currentSerialPortInfo, currentSerialPorts) { if (currentSerialPortInfo.portName() == serialPortInfo.portName()) { found = true; break; } } if (!found) { qDebug() << "Serial port" << serialPortInfo.portName() << "was removed."; } } serialPorts = currentSerialPorts; }); return a.exec(); } ``` 上面的代码首先枚举当前可用的串口,并创建一个QSerialPort对象并打开串口。然后监听串口热插拔事件,并在事件发生时输出相关信息。其中,QSerialPortInfo::availablePortsChanged信号在串口热插拔事件发生时会被触发,可以用connect函数将其与一个槽函数连接起来。 需要注意的是,QSerialPortInfo::availablePortsChanged信号在Windows操作系统下并不是实时触发的,而是有一定的延迟。如果需要实现更加实时热插拔检测,可以考虑使用Qt的winEvent函数或者使用WinAPI函数来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值