我编写了一个工作测试程序来监控 USB 设备的连接/断开连接。就我而言,这是一个读卡器,系统将其识别为 USB 输入设备和 HID USB。但是有一个难以理解的时刻 - 当我的插槽被触发(参见下面的代码)Dialog::SlotArrived并且Dialog::SlotRemoved文本仅在第一次更改时。但是,如果您将鼠标指针移到 thisQLabel上,则会重新绘制它。找到了出路——QLabel::setText如果放置后QLabel::repaint,那么渲染是正常的。下面是项目的正文。你能告诉我我哪里写错了吗...
使用 Qt 5.14.1,С++17,编译器版本 19.16.27035 来自 studio 2017
UsbTestWatcher.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
dialog.cpp
HEADERS += \
dialog.h
LIBS += -lUser32
# Fuck windows-1251 !!!
QMAKE_EXTRA_TARGETS += before_build makefilehook
makefilehook.target = $(MAKEFILE)
makefilehook.depends = .beforebuild
PRE_TARGETDEPS += .beforebuild
before_build.target = .beforebuild
before_build.depends = FORCE
before_build.commands = chcp 1251
主文件
#include <QApplication>
#include "dialog.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
对话框.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QtWidgets>
#include <dbt.h>
class Dialog : public QDialog {
Q_OBJECT
QLabel *L;
bool nativeEvent(const QByteArray& eventType, void *message, long *result);
public:
Dialog(QWidget *parent = nullptr);
~Dialog() {}
public slots:
void SlotRegister();
void SlotArrived(QString iName);
void SlotRemoved(QString iName);
signals:
void SigUsbArrived(QString iName);
void SigUsbRemoved(QString iName);
};
#endif // DIALOG_H
对话框.cpp
#include "dialog.h"
//
// Можно расширить своими классами USB-устройств, тех которые нужно отслеживать
//
static const GUID GUID_DEVINTERFACE_LIST[] = {
// USB Raw Device Interface Class GUID
{ 0xa5dcbf10, 0x6530, 0x11d2, {0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed}},
// Disk Device Interface Class GUID
{ 0x53f56307, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}},
// Human Interface Device Class GUID
{ 0x4d1e55b2, 0xf16f, 0x11Cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}},
// FTDI_D2XX_Device Class GUID
{ 0x219d0508, 0x57a8, 0x4ff5, {0x97, 0xa1, 0xbd, 0x86, 0x58, 0x7c, 0x6c, 0x7e}},
// FTDI_VCP_Device Class GUID
{ 0x86e0d1e0, 0x8089, 0x11d0, {0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73}}
};
Dialog::Dialog(QWidget *parent)
: QDialog(parent) {
L = new QLabel("Можно читать список usb-устройств при старте ...");
QVBoxLayout *H = new QVBoxLayout();
H->addWidget(L);
setLayout(H);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
connect(this, &Dialog::SigUsbArrived, this, &Dialog::SlotArrived);
connect(this, &Dialog::SigUsbRemoved, this, &Dialog::SlotRemoved);
QTimer::singleShot(100, this, &Dialog::SlotRegister);
}
void Dialog::SlotRegister() {
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
HWND hw = (HWND) this->effectiveWinId();
for (size_t i = 0; i < sizeof(GUID_DEVINTERFACE_LIST) / sizeof(GUID); i++) {
NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];
HDEVNOTIFY hDevNotify = RegisterDeviceNotification(hw, &NotificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE);
if (!hDevNotify) {
QMessageBox::critical(this, "Ошибка", "Ошибка регистрации уведомителя!");
emit close();
}
}
}
void Dialog::SlotArrived(QString iName) {
L->setText(QString("Подключено: %1").arg(iName));
L->repaint();
qDebug() << QString("Подключено: %1").arg(iName);
}
void Dialog::SlotRemoved(QString iName) {
L->setText(QString("Отключено: %1").arg(iName));
L->repaint();
qDebug() << QString("Отключено: %1").arg(iName);
}
bool Dialog::nativeEvent([[maybe_unused]] const QByteArray& eventType, void *message,
[[maybe_unused]] long *result) {
MSG *msg = static_cast< MSG * >(message);
int msgType = msg->message;
if (msgType == WM_DEVICECHANGE) {
if (msg->wParam == DBT_DEVICEARRIVAL || msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE) lpdb;
if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
QString path = QString::fromWCharArray(lpdbv->dbcc_name);
if (msg->wParam == DBT_DEVICEARRIVAL)
emit SigUsbArrived(path);
else
emit SigUsbRemoved(path);
return true;
}
}
}
return false;
}
唉,但这一切的罪魁祸首竟然是(很可能)
VMWare Workstation 14.0。Qt/C++我有一个部署在来宾系统中的工作环境。我部署了发布版本并将它们上传到主机 - 在那里渲染结果没有失败。为什么是“最有可能”?来宾系统Win 7 x64,主机系统Win 10 x64。没有进一步试验的余地。