1、主要功能
- 通过继承QAbstractNativeEventFilter接口实现串口热插拔监测功能;
- 通过在QWidget中重写nativeEvent实现串口热插拔监测功能;
- 通过一个函数获取系统中所有可用串口名;
- 自动添加、移除可用串口。
2、适用系统
3、源码地址
4、实现效果
5、实现代码
#ifndef COMCHANGE_H
#define COMCHANGE_H
#include <QObject>
#include <qabstractnativeeventfilter.h>
#include <windows.h>
#include "dbt.h"
class ComChange : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
static ComChange* getInstance();
static QStringList getAvailablePort();
void setHWND(HWND hwnd);
private:
explicit ComChange(QObject *parent = nullptr);
protected:
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
signals:
void comStatus(QString name, bool flag);
private:
static ComChange* m_comChange;
HWND m_hwnd;
};
#endif
#include "comchange.h"
#include <QApplication>
#include <QMutex>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <qdebug.h>
ComChange* ComChange::m_comChange = nullptr;
ComChange *ComChange::getInstance()
{
if(m_comChange == nullptr)
{
static QMutex mutex;
QMutexLocker locker(&mutex);
if(m_comChange == nullptr)
{
m_comChange = new ComChange();
}
}
return m_comChange;
}
QStringList ComChange::getAvailablePort()
{
QStringList strName;
foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts())
{
QSerialPort port(info);
if(port.open(QIODevice::ReadWrite))
{
strName << info.portName();
port.close();
}
}
return strName;
}
void ComChange::setHWND(HWND hwnd)
{
this->m_hwnd = hwnd;
}
ComChange::ComChange(QObject *parent) : QObject(parent)
{
qApp->installNativeEventFilter(this);
}
bool ComChange::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
MSG* msg = reinterpret_cast<MSG*>(message);
if(msg->message == WM_DEVICECHANGE
&& msg->hwnd == this->m_hwnd)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch (msg->wParam)
{
case DBT_DEVICEARRIVAL:
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name);
emit comStatus(strName, true);
}
break;
}
case DBT_DEVICEREMOVECOMPLETE:
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name);
emit comStatus(strName, false);
}
break;
}
default:
break;
}
}
return false;
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
void on_comStatus(QString name, bool flag);
private:
Ui::Widget *ui;
};
#endif
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <windows.h>
#include "dbt.h"
#include "comchange.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ComChange::getInstance()->setHWND((HWND)this->winId());
connect(ComChange::getInstance(), &ComChange::comStatus, this, &Widget::on_comStatus);
ui->comboBox->addItems(ComChange::getAvailablePort());
}
Widget::~Widget()
{
delete ui;
}
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
MSG* msg = reinterpret_cast<MSG*>(message);
if(msg->message == WM_DEVICECHANGE)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch (msg->wParam)
{
case DBT_DEVICEARRIVAL:
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name);
qDebug() << strName;
}
break;
}
case DBT_DEVICEREMOVECOMPLETE:
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name);
qDebug() << strName;
}
break;
}
default:
break;
}
}
return false;
}
void Widget::on_comStatus(QString name, bool flag)
{
if(flag)
{
ui->comboBox->addItem(name);
}
else
{
ui->comboBox->removeItem(ui->comboBox->findText(name));
}
}