Windows 系统
Qt5.4
c++语言
让程序运行过程中能监测某一USB设备的拔插状态,当设备被拔出时进行相关处理。
见 MSDN Device Messages 说明:
For each device event, the system broadcasts a WM_DEVICECHANGE message to all applications. In this message, the wParam parameter identifies the device event type and the lParam parameter is a pointer to event-specific data.
然而, WM_DEVICECHANGE 消息只会通知给TOP窗口,见 Detecting Media Insertion or Removal说明:
Windows sends all top-level windows a set of default WM_DEVICECHANGE messages when new devices or media (such as a CD or DVD) are added and become available, and when existing devices or media are removed.
但软件运行过程中TOP窗口并不固定,因此,选择一个软件开启到退出都会一直存在,不会析构的窗口注册消息来获取想要的消息通知。
注册消息用到函数是 RegisterDeviceNotification:
/*
winuser.h 头文件定义:如果是 unicode 编码,
则用 RegisterDeviceNotificationW,
其他则用 RegisterDeviceNotificationA
*/
HDEVNOTIFY RegisterDeviceNotificationW(
HANDLE hRecipient, //指向窗口或服务的句柄
LPVOID NotificationFilter, //接受设备通知句柄
DWORD Flags //说明 hRecipient 是用的窗口句柄还是设备服务句柄
);
NotificationFilter:
A pointer to a block of data that specifies the type of device for which notifications should be sent. This block always begins with the DEV_BROADCAST_HDR structure. The data following this header is dependent on the value of the dbch_devicetype member, which can be DBT_DEVTYP_DEVICEINTERFACE or DBT_DEVTYP_HANDLE.
DBT_DEVTYP_DEVICEINTERFACE:
Class of devices. This structure is a DEV_BROADCAST_DEVICEINTERFACE structure.
MSDN 例子中 NotificationFilter 参数用的是 DEV_BROADCAST_DEVICEINTERFACE 结构体,指明设备类型为设备接口类 DBT_DEVTYP_DEVICEINTERFACE 以及用来注册消息的 device interface class GUID。不同GUID说明见USB设备的插入检测
Flags:
DEVICE_NOTIFY_WINDOW_HANDLE: hRecipient is a windows handle
DEVICE_NOTIFY_SERVICE_HANDLE: hRecipient is a service status handle
//注册消息需要添加头文件
#include
#include
//注册消息
bool CLogin::RegisterHIVDeviceNotification()
{
HDEVNOTIFY hDeviceNotify;
/*
*这里注册的设备是 Human Interface Devices (HID) 类
*GUID_DEVINTERFACE_HID = {4D1E55B2-F16F-11CF-88CB-001111000030}
*/
GUID guid_hiv = {0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
HWND hWnd = (HWND)(this->winId()); //获取当前窗口句柄
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = guid_hiv;
hDeviceNotify = RegisterDeviceNotification (hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (NULL == hDeviceNotify)
return false;
else
return true; //注册消息成功
}
//处理接受到的消息
// nativeEvent 是重载的虚函数
bool CLogin::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType); //未用该参数
Q_UNUSED(result); //未用该参数
MSG *msg = reinterpret_cast<MSG*>(message);
//消息类型是 设备改变 且为 设备拔出
if (msg->message == WM_DEVICECHANGE && msg->wParam == DBT_DEVICEREMOVECOMPLETE)
{
emit SigDeviceRemove(); //发送信号处理
}
return false;
}
返回 false 表示消息继续传递,开始在消息处理后返回 true ,结果界面为空白,没明白原因???
用事件过滤器时处理完消息返回true都没问题
参考: Qt: usb热插拔检测(windows) 里介绍方法,用 nativeEventFilter 来处理消息,在主程序main.cpp中安装事件过滤器 installNativeEventFilter。
实现函数 nativeEventFilter 的类需要继承 QAbstractNativeEventFilter,之前用该方法没成功实现,用该方法时未注册消息,以后补充。