Qt-windows-检测USB设备插拔,获取PID | VID

该代码实现了一个名为ZUSBWatch的Qt窗口类,用于监听USB设备的连接和断开。它注册了设备通知以捕获设备插入和移除事件,特别是关注特定VID和PID的USB设备。当设备状态变化时,ZUSBWatch会发射相应的信号,如USBConnected和USBDisconnected,供其他部件响应处理。此外,它还处理串口(COM端口)的连接和断开事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Watch类,声明一个usbDevice结构体与观测类

#pragma once

#include <QWidget>
#include <QAbstractNativeEventFilter>
#include <windows.h>
#include <dbt.h>
#include "QMainWindow"

class usbDevice;
class ZUSBWatch : public QMainWindow
{
	Q_OBJECT
public:
	ZUSBWatch();
	bool start(const uint16_t vid = 0, const uint16_t pid = 0, const QString sn = "");
	bool stop();
signals:
	void USBConnected(usbDevice name);
	void USBDisconnected(usbDevice name);
	void PortConnected(QString portName);
	void PortDisconnected(QString portName);

protected:
	virtual bool nativeEvent(const QByteArray& eventType,
		void* message,
		long* result);

	bool getDevData(LPARAM lParamDev, usbDevice& newDevice);
	inline QString getQstring(void* stringPtr);

private:
	HDEVNOTIFY      devNotify;
	usbDevice*      targetDev;
};


class usbDevice {
public:
	usbDevice() : VID(0), PID(0) { }
	usbDevice(uint16_t vid, uint16_t pid, QString sn);
	bool operator==(const usbDevice& other) const;
	bool operator!=(const usbDevice& other) const;
	operator QString() const;

	uint16_t VID;           // the device Vendor ID (16 bit value)
	uint16_t PID;           // the device Product ID (16 bit value)
	QString  serialNum;     // the device serial number
	QString  Manufacturer;  // the device manufacturer name
	QString  Product;       // the device product name
	QString  descriptionName;
};
Q_DECLARE_METATYPE(usbDevice);
#include "zdevicewatch.h"
#include <QDebug>
#include <QRegularExpression>
#include <SetupAPI.h>
#include <devguid.h>
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#pragma comment(lib, "user32.lib")
ZUSBWatch::ZUSBWatch() : QMainWindow() {
	devNotify = NULL;
	targetDev = NULL;
}

bool ZUSBWatch::start(const uint16_t vid, const uint16_t pid, const QString sn) {
	targetDev = new usbDevice(vid, pid, sn);

	GUID usbGUID[] = {
		{ 0xa5dcbf10, 0x6530, 0x11d2, { 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed } },     // All USB Devices
		{ 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },
		{ 0x4d1e55b2, 0xf16f, 0x11Cf, { 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },
		{ 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } },
		{ 0x219d0508, 0x57a8, 0x4ff5, { 0x97, 0xa1, 0xbd, 0x86, 0x58, 0x7c, 0x6c, 0x7e } },
		{ 0x4d36e967, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } },     // COM PORTS
		{0x86e0d1e0L, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },
	};

	DEV_BROADCAST_DEVICEINTERFACE notificationFilter;

	memset(&notificationFilter, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
	notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
	notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
	notificationFilter.dbcc_classguid = usbGUID[0];

	devNotify = RegisterDeviceNotification((HANDLE)this->winId(),
		&notificationFilter,
		DEVICE_NOTIFY_WINDOW_HANDLE);

	return devNotify != NULL;
}

bool ZUSBWatch::stop() {
	// clear out target device and pre-laod return value
	if (targetDev != NULL) {
		delete targetDev;
		targetDev = NULL;
	}
	bool success = true;

	// Don't dallocate a NULL notification handle. output any errors.
	if (devNotify != NULL) {
		success = UnregisterDeviceNotification(devNotify);
		devNotify = NULL;
		if (!success) {
			DWORD err = GetLastError();     // error from last call
			LPVOID msgBuf;                  // buffer to hold error message

			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
				FORMAT_MESSAGE_FROM_SYSTEM |
				FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, err, 0, (LPTSTR)&msgBuf, 0, NULL);

			//qDebug() << "UNREGISTER_DEVICE_NOTIFICATION FAILED WITH ERROR " << err
			//	<< ": " << QString::fromStdWString((LPTSTR)msgBuf);

			LocalFree(msgBuf);
		}
	}
	return success;
}

bool ZUSBWatch::nativeEvent(const QByteArray& eventType,
	void* message,
	long* result)
{
	Q_UNUSED(result);
	Q_UNUSED(eventType);
	MSG* msg = reinterpret_cast<MSG*>(message);
	if (msg->message == WM_DEVICECHANGE) {
		if (msg->wParam == DBT_DEVICEARRIVAL) {
			if (reinterpret_cast<DEV_BROADCAST_HDR*>(msg->lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
				usbDevice newDev;
				if (getDevData(msg->lParam, newDev)) {
					emit this->USBConnected(newDev);
				}
			}
			else if (reinterpret_cast<DEV_BROADCAST_HDR*>(msg->lParam)->dbch_devicetype == DBT_DEVTYP_PORT) {
				DEV_BROADCAST_PORT* port = reinterpret_cast<DEV_BROADCAST_PORT*>(msg->lParam);
				emit this->PortConnected(getQstring(port->dbcp_name));
			}
		}
		else if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {

			if (reinterpret_cast<DEV_BROADCAST_HDR*>(msg->lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
				usbDevice newDev;
				if (getDevData(msg->lParam, newDev)) {
					emit this->USBDisconnected(newDev);
				}
			}
			else if (reinterpret_cast<DEV_BROADCAST_HDR*>(msg->lParam)->dbch_devicetype == DBT_DEVTYP_PORT) {
				DEV_BROADCAST_PORT* port = reinterpret_cast<DEV_BROADCAST_PORT*>(msg->lParam);
				emit this->PortDisconnected(getQstring(port->dbcp_name));
			}
		}
	}

	// return false to let Qt handle the rest
	return false;
}

bool ZUSBWatch::getDevData(LPARAM lParamDev, usbDevice& newDevice) {
	bool success = false;       // return value
	DEV_BROADCAST_DEVICEINTERFACE* deviceStruct = reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lParamDev);

	// split windows devicename along #. should give us:
	//      0) Device Type (USB we hope)
	//      1) VID, PID, etc...
	//      2) Serial Number String
	//      3) Class GUID as a string
	// ex: \\?\USB#VID_03EB&PID_2111#ATML1802021800002211#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
	QStringList substr = getQstring(deviceStruct->dbcc_name).split("#");

	// Only deal with USB devices, other things could pop up?
	if (substr.at(0).contains("USB") || substr.at(0).contains("usb")) {
		// Get serial number & GUID
		newDevice.serialNum = substr.at(2);
		//newDevice.class_guid = deviceStruct->dbcc_classguid;

		// Get VID and PID
		int vid_idx = substr.at(1).indexOf(QRegularExpression("VID_[\\da-fA-F]{4}"));
		int pid_idx = substr.at(1).indexOf(QRegularExpression("PID_[\\da-fA-F]{4}"));

		if (vid_idx >= 0) {
			newDevice.VID = substr.at(1).mid(vid_idx + 4, 4).toUShort(&success, 16);
		}
		if (pid_idx >= 0 && success) {
			newDevice.PID = substr.at(1).mid(pid_idx + 4, 4).toUShort(&success, 16);
		}

		if (targetDev != NULL) {
			success = (newDevice == *targetDev);
		}
	}
	return success;
}

inline QString ZUSBWatch::getQstring(void* stringPtr) {
#ifdef UNICODE
	return QString::fromStdWString((LPCTSTR)stringPtr);
#else
	return QString::fromStdString((std::string)stringPtr);  // ?? not sure if correct
#endif
}


usbDevice::usbDevice(uint16_t vid, uint16_t pid, QString sn) {
	VID = vid;
	PID = pid;
	serialNum = sn;
}

bool usbDevice::operator==(const usbDevice& other) const {
	bool vidMatch = other.VID == 0 || this->VID == other.VID;
	bool pidMatch = other.PID == 0 || this->PID == other.PID;
	bool snMatch = other.serialNum.isEmpty() || this->serialNum == other.serialNum;
	return vidMatch && pidMatch && snMatch;
}

bool usbDevice::operator!=(const usbDevice& other) const {
	return !(*this == other);
}

usbDevice::operator QString() const {
	return QString("0x%1 : 0x%2 : %3").arg(VID, 4, 16, QLatin1Char('0')).arg(PID, 4, 16, QLatin1Char('0')).arg(serialNum);
}

使用:

 

void ZCameraManage::initConnect()
{
	//start usb watch
	m_deviceWater->start();
	connect(m_deviceWater, &ZUSBWatch::USBConnected, this, &ZCameraManage::onUsbConnect);
	connect(m_deviceWater, &ZUSBWatch::USBDisconnected, this,         &ZCameraManage::onUsbDisConnect);
}


void ZCameraManage::onUsbConnect(usbDevice dev)
{
	QString vid = QString("0x%1").arg(dev.VID, 4, 16, QLatin1Char('0'));
	QString pid = QString("0x%1").arg(dev.PID, 4, 16, QLatin1Char('0'));
	if (m_trustDevice.contains(vid) && m_trustDevice[vid] == pid)
	{
		zInfo("device connect", "");
		zInfo("serialNum : ", dev.serialNum);
		zInfo("pid : ", pid);
		zInfo("vid : ", vid);
		emit sigDeviceConnect();
	}
}

void ZCameraManage::onUsbDisConnect(usbDevice dev)
{
	QString vid = QString("0x%1").arg(dev.VID, 4, 16, QLatin1Char('0'));
	QString pid = QString("0x%1").arg(dev.PID, 4, 16, QLatin1Char('0'));
	if (m_trustDevice.contains(vid) && m_trustDevice[vid] == pid)
	{
		zInfo("device disConnect", "");
		zInfo("serialNum : ", dev.serialNum);
		zInfo("pid : ", pid);
		zInfo("vid : ", vid);
		emit sigDeviceDisconnect();
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值