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(¬ificationFilter, 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(),
¬ificationFilter,
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();
}
}