Qt之移动硬盘热插拔监控
最近在做一个通用对话框,类似于windows的资源管理器,当然了没有windwos资源管理器那么强大。用户报了一个bug,说通用对话框打开之后不能实时监控U盘插入,随手在百度上搜索了一圈,这个问题还是挺多人在搞,都大同小异,基本都是监控windows的事件。下面说下我自己解决该问题的流程。
一、windows消息
WM_DEVICECHANGE:附上WM_DEVICECHANGE消息的链接,此消息意思是当计算机的硬件配置或者设备发生变化时通知应用程序,此消息下在wParam参数中包含了此事件的事件类型。英文:Notifies an application of a change to the hardware configuration of a device or the computer.
此消息类型下的事件类型有12个,如下表所示
|
A request to change the current configuration (dock or undock) has been canceled. |
更改当前配置的请求已被取消 |
|
The current configuration has changed, due to a dock or undock. |
由于插入或移除,当前的配置已经改变。 |
|
A custom event has occurred. |
定制事件 |
|
A device or piece of media has been inserted and is now available. |
插入新的设备 |
|
Permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal. |
请求移除设备,可以失败 |
|
A request to remove a device or piece of media has been canceled. |
去除中断 |
|
A device or piece of media has been removed. |
设备被移除 |
|
A device or piece of media is about to be removed. Cannot be denied. |
即将删除,仍然有效 |
|
A device-specific event has occurred. |
发生设备特定的事件 |
|
A device has been added to or removed from the system. |
设备被新增或者移除 |
|
Permission is requested to change the current configuration (dock or undock). |
请求权限来更改当前的配置 |
|
The meaning of this message is user-defined. |
此消息的含义是用户定义的 |
上表所示的消息中我们用到了其中3个事件,这三个事件分别在合适的时机来获取优盘事件;初次之外还可以监控DBT_DEVNODES_CHANGED事件,此事件在优盘插拔时不止一次的响应,如果用户需要区分插拔事件则此事件不可以。
DBT_DEVICEARRIVAL://检测到新设备
DBT_DEVICEREMOVECOMPLETE://设备被移除
DBT_CUSTOMEVENT://右键弹出设备时响应,此事件只有用户进行注册过后才会收到
二、注册设备通知
注册设备状态发生变化时通知,需要使用RegisterDeviceNotification接口,注册方法代码如下,关键注释都有,就不解释了。
bool diskoperate::registerDisk(const QString & cDiskName)
{
if (!IsDiskExist(cDiskName.at().toLatin1()))
{
return false;
} const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);//不弹出系统提示
HANDLE handle = CreateFile(
cDiskName.toStdWString().c_str() ,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
);//拿到盘符句柄
if (handle == nullptr)
{
return false;
}
DEV_BROADCAST_HANDLE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof (NotificationFilter) );
NotificationFilter.dbch_size = sizeof (DEV_BROADCAST_HANDLE );
NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
NotificationFilter.dbch_handle = handle;
HDEVNOTIFY hDevNotify = RegisterDeviceNotification((HWND)this->winId()
, &NotificationFilter
, DEVICE_NOTIFY_WINDOW_HANDLE);//注册设备通知 CloseHandle(handle);//关闭盘符句柄
::SetErrorMode(oldmode);//恢复之前错误模式
if (!hDevNotify)
{
return false;
} m_lstMoveDrive[cDiskName.at()] = hDevNotify; return true;
}
上述方法中用了一个判断当前盘符是否存在的函数IsDiskExist,此函数也比较简单,用过GetLogicalDrives接口获取当前系统已有盘符,进行比较即可。
bool IsDiskExist(char cDiskName)
{
DWORD dwDrivers;
int i = toupper(cDiskName) - 'A'; //dwDrivers的每一个二进制位表示对应的驱动器是否存在。
dwDrivers = GetLogicalDrives();
//判断当前位是否有驱动器
if ((dwDrivers & ( << (i))) != )
{
return true;
}
return false;
}
三、获取系统事件
Qt给我们提供了一个QAbstractNativeEventFilter类,该类可以过滤应用程序的所有事件,因此我们的类需要继承并实现此类中的nativeEventFilter方法,在此方法中进行事件过滤,之前写过一个相关的文章qt捕获全局windows消息可以进行参考下,,nativeEventFilter方法想要进行事件过滤,我们必须使用qApp->installNativeEventFilter(this);方法进行注册我们自己写的类。
bool diskoperate::nativeEventFilter( const QByteArray &eventType, void *message, long *result )
{
if ("windows_dispatcher_MSG" == eventType
|| "windows_generic_MSG" == eventType)
{
MSG * msg = reinterpret_cast<MSG *>(message);
if(msg->message == WM_DEVICECHANGE)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch(msg->wParam)
{
case DBT_DEVICEARRIVAL://检测到新设备
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
qDebug() << "DBT_DEVICEARRIVAL";
updateMoveDrives();
}
break;
case DBT_DEVICEQUERYREMOVE://请求移除设备,可能失败 此时刷新不会让移动设备消失
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
qDebug() << "DBT_DEVICEQUERYREMOVE";
}
break;
case DBT_DEVICEQUERYREMOVEFAILED://去除中断
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
qDebug() << "DBT_DEVICEQUERYREMOVEFAILED";
}
break;
case DBT_DEVICEREMOVEPENDING://即将删除,仍然有效
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
qDebug() << "DBT_DEVICEREMOVEPENDING";
}
break;
case DBT_DEVICEREMOVECOMPLETE://设备不见了
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
qDebug() << "DBT_DEVICEREMOVECOMPLETE";
updateMoveDrives();
}
break;
case DBT_CUSTOMEVENT:
if (lpdb->dbch_devicetype == DBT_DEVTYP_HANDLE)
{
qDebug() << "DBT_CUSTOMEVENT";
updateMoveDrives();
}
break;
case DBT_DEVNODES_CHANGED:
qDebug() << "DBT_DEVNODES_CHANGED";
updateMoveDrives();
break;
default:
qDebug() << msg->wParam;
}
outputDrives();
}
} return __super::nativeEvent(eventType, message, result);
}
四、运行效果
如下图1所示,一次完整的优盘插入、弹出和删除,所触发的系统事件

图1 测试截图
五、下载连接
相关连接:
2、接收不到DBT_DEVICEQUERYREMOVE消息怎么办?
Qt之移动硬盘热插拔监控的更多相关文章
- Qt之键盘事件监听-实时响应大小写Capslock按键
目录 一.开篇 二.效果展示 三.实现思路 1.重写QLlinEdit 2.全局应用程序事件 3.windows钩子 四.相关文章 原文链接:Qt之键盘事件监听-实时响应大小写Capslock按键 一 ...
- QT GUI总结
QT提供了设计师工具,可以很方便的使用鼠标拖拽的方式绘制界面.绘制完毕后自动生成一个界面的.h文件(如ui_mainwindow.h),其中含有一个自动生成的Ui_MainWindow类,这个类中 ...
- 我用STM32MP1做了个疫情监控平台4—功能完善界面重新设计
目录 前言 界面展示 新增功能 API 接口说明 多个接口数据的获取和解析 FontAwesome字体图标库的使用 代码下载 系列教程 @ 前言 之前我用STM32MP1和Qt实现了疫情监控平台,系列 ...
- Qt: usb热插拔检测(windows);
Qt提供了QAbstractNativeEventFilter来实现本地时间得过滤,通过对本地事件的检测,判断usb热插拔:(这里是windows 的例子); 首先,以QWidget, QAbstra ...
- 5、Qt Project之键盘数据监控
键盘数据监控: 同样的,键盘的检测和鼠标的情形很类似,都是以QWidget为基类的工程 Step1:在UI设计中添加该模块需要使用的相关组件,如下所示: <width>141</wi ...
- 2、Qt Project之鼠标事件监控
鼠标事件监控: 对于鼠标时间监控的相关操作,我们在简历工程的时候需要选择的是QWidget基类,不选择QMainWindow基类,如下所示: Base class:QWidget Step1:我们首先 ...
- Qt编写视频监控画面分割界面(开源)
其实qt应用在安防领域还是蛮多的,尤其是视频监控系统,但是网上几乎没有看到qt做的最基础的视频监控画面分割的demo,今天特意花几分钟提取出来,开源放出来.欢迎大家多多点赞!源码下载:点击打开链接 运 ...
- Qt编写的RTSP播放器+视频监控(android版本)
之前写过vlc版本,ffmpeg版本,也在linux上和嵌入式linux上跑过视频监控,这次想直接用ffmpeg的库写个android版本,qt+ffmpeg+android直接用之前的qt+ffmp ...
- Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)
一.自定义控件大全 (一).控件介绍 超过160个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...
随机推荐
- android堆栈调试--详细
1.将ndk中的arm-linux-androideabi-addr2line可执行文件的路径加入配置文件~/.bashrc中,例如: export PATH=$PATH:~/dlna/android ...
- Spring框架——IOC依赖注入
本来想把IOC和AOP一起介绍的,但是AOP内容太多了,所以就分开了,最后的结果就是这一篇只剩下一点点了.这不是第一次写关于IOC的文章了,之前写过Java反射,Java注解,也写过通过XML解析实现 ...
- 六、Hadoop学习笔记————调优之操作系统以及JVM
内核参数overcommit_memory 它是 内存分配策略 可选值:0.1.2.0, 表示内核将检查是否有足够的可用内存供应用进程使用:如果有足够的可用内存,内存申请允许:否则,内存申请失败,并 ...
- 深入了解Android蓝牙Bluetooth——《进阶篇》
在 [深入了解Android蓝牙Bluetooth--<基础篇>](http://blog.csdn.net/androidstarjack/article/details/6046846 ...
- Android自定义指示器时间轴
指示器时间轴在外卖.购物类的APP里会经常用到,效果大概就像下面这样,看了网上很多文章,大都是自己绘制,太麻烦,其实通过ListView就可以实现. 在Activity关联的布局文件activit ...
- RAC环境下误操作将数据文件添加到本地存储
今天碰到个有意思的事情,有客户在Oracle RAC环境,误操作将新增的数据文件直接创建到了其中一个节点的本地存储上. 发现网上去搜的话这种问题还真不少,对应解决方案也各式各样,客户问我选择哪种方案可 ...
- django框架中的form组件的用法
form组件的使用 先导入: from django.forms import Form from django.forms import fields from django.forms impor ...
- angularjs 给封装的模态框元素传值,和实现兄弟传值
本例实现封装的元素所放的位置不同,而选择不同的传值,这里举例封装了bootstrap模态框,以后也方便大家去直接使用.方法举例如下:首先主页调用css/js有: <link rel=" ...
- 项目实战11—企业级nosql数据库应用与实战-redis的主从和集群
企业级nosql数据库应用与实战-redis 环境背景:随着互联网2.0时代的发展,越来越多的公司更加注重用户体验和互动,这些公司的平台上会出现越来越多方便用户操作和选择的新功能,如优惠券发放.抢红包 ...
- Netty4 学习笔记之三:粘包和拆包
前言 在上一篇Netty 心跳 demo 中,了解了Netty中的客户端和服务端之间的心跳.这篇就来讲讲Netty中的粘包和拆包以及相应的处理. 名词解释 粘包: 会将消息粘粘起来发送.类似吃米饭,一 ...