1 背景
最近为自己使用的资源管理实现U盘动态检测插拔功能,通过在网上查资料,发现在Windows下,当插拔磁盘时Windows会给应用发送广播消息WM_DEVICECHANGE通知各应用设备发生变化了,应用可以根据该消息来检测U盘动态插拔。下面讲述在Qt下如何检测WM_DEVICECHANGE消息,并检测U盘插拔。
2 Qt处理Windows消息
Windows消息是发送给窗口的,在Qt下窗口就是QWidget,QWidget有一个protected类型虚函数nativeEvent来处理平台本地消息,函数原型如下:
[virtual protected] bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
在Windows平台下各参数意义如下:
eventType : "windows_generic_MSG"
message: MSG *
result: LRESULT
可以重载该函数来处理WM_DEVICECHANGE消息。
3 实现
从QWidget派生一个类型Widget,如下所示:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
bool nativeEvent(const QByteArray &eventType,
void *message,
long *result) override;
};
实现虚函数nativeEvent
bool Widget::nativeEvent(const QByteArray &eventType,
void *message,
long *result)
{
Q_UNUSED(eventType)
MSG* msg = (MSG*)message;
if(msg->message == WM_DEVICECHANGE)
{
if(msg->wParam == DBT_DEVICEARRIVAL)
{
PDEV_BROADCAST_HDR devHdr = (PDEV_BROADCAST_HDR)msg->lParam;
if(devHdr->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
//U盘插入, 更新驱动器列表
}
*result = 0;
}
else if(msg->wParam == DBT_DEVICEREMOVECOMPLETE)
{
PDEV_BROADCAST_HDR devHdr = (PDEV_BROADCAST_HDR)msg->lParam;
if(devHdr->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
//U盘拔出, 更新驱动器列表
}
*result = 0;
}
}
return false;//返回false表明该消息接着向下传递,以便其它应用处理该消息。
}
如上所示将参数message转换为MSG*类型msg,通过检测msg的成员message,wParam和lParam类型来判断U盘插拔。
- msg成员message是否是WM_DEVICECHANGE类型, 如果是则检测msg的wParam参数。
- 如果wParam是DBT_DEVICEARRIVAL表明设备插入,是DBT_DEVICEREMOVECOMPLETE表明设备拔出。
- 如何检测设备是U盘而不是鼠标/键盘以及其它设备呢?这就需要通过msg参数lParam判断了。如果lParam类型为DBT_DEVTYP_VOLUME就表明设备是U盘。