最近在做一个通用对话框,类似于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个,如下表所示

DBT_CONFIGCHANGECANCELED
0x0019

A request to change the current configuration (dock or undock) has been canceled.

更改当前配置的请求已被取消

DBT_CONFIGCHANGED
0x0018

The current configuration has changed, due to a dock or undock.

由于插入或移除,当前的配置已经改变。

DBT_CUSTOMEVENT
0x8006

A custom event has occurred.

定制事件

DBT_DEVICEARRIVAL
0x8000

A device or piece of media has been inserted and is now available.

插入新的设备

DBT_DEVICEQUERYREMOVE
0x8001

Permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal.

请求移除设备,可以失败

DBT_DEVICEQUERYREMOVEFAILED
0x8002

A request to remove a device or piece of media has been canceled.

去除中断

DBT_DEVICEREMOVECOMPLETE
0x8004

A device or piece of media has been removed.

设备被移除

DBT_DEVICEREMOVEPENDING
0x8003

A device or piece of media is about to be removed. Cannot be denied.

即将删除,仍然有效

DBT_DEVICETYPESPECIFIC
0x8005

A device-specific event has occurred.

发生设备特定的事件

DBT_DEVNODES_CHANGED
0x0007

A device has been added to or removed from the system.

设备被新增或者移除

DBT_QUERYCHANGECONFIG
0x0017

Permission is requested to change the current configuration (dock or undock).

请求权限来更改当前的配置

DBT_USERDEFINED
0xFFFF

The meaning of this message is user-defined.

此消息的含义是用户定义的

上表所示的消息中我们用到了其中3个事件,这三个事件分别在合适的时机来获取优盘事件;初次之外还可以监控DBT_DEVNODES_CHANGED事件,此事件在优盘插拔时不止一次的响应,如果用户需要区分插拔事件则此事件不可以。

DBT_DEVICEARRIVAL://检测到新设备

DBT_DEVICEREMOVECOMPLETE://设备被移除

DBT_CUSTOMEVENT://右键弹出设备时响应,此事件只有用户进行注册过后才会收到

二、注册设备通知

注册设备状态发生变化时通知,需要使用RegisterDeviceNotification接口,注册方法代码如下,关键注释都有,就不解释了。

  1. bool diskoperate::registerDisk(const QString & cDiskName)
  2. {
  3. if (!IsDiskExist(cDiskName.at().toLatin1()))
  4. {
  5. return false;
  6. }
  7.  
  8. const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);//不弹出系统提示
  9. HANDLE handle = CreateFile(
  10. cDiskName.toStdWString().c_str() ,
  11. GENERIC_READ,
  12. FILE_SHARE_READ | FILE_SHARE_WRITE,
  13. ,
  14. OPEN_EXISTING,
  15. FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
  16. );//拿到盘符句柄
  17. if (handle == nullptr)
  18. {
  19. return false;
  20. }
  21. DEV_BROADCAST_HANDLE NotificationFilter;
  22. ZeroMemory( &NotificationFilter, sizeof (NotificationFilter) );
  23. NotificationFilter.dbch_size = sizeof (DEV_BROADCAST_HANDLE );
  24. NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
  25. NotificationFilter.dbch_handle = handle;
  26. HDEVNOTIFY hDevNotify = RegisterDeviceNotification((HWND)this->winId()
  27. , &NotificationFilter
  28. , DEVICE_NOTIFY_WINDOW_HANDLE);//注册设备通知
  29.  
  30. CloseHandle(handle);//关闭盘符句柄
  31. ::SetErrorMode(oldmode);//恢复之前错误模式
  32. if (!hDevNotify)
  33. {
  34. return false;
  35. }
  36.  
  37. m_lstMoveDrive[cDiskName.at()] = hDevNotify;
  38.  
  39. return true;
  40. }

上述方法中用了一个判断当前盘符是否存在的函数IsDiskExist,此函数也比较简单,用过GetLogicalDrives接口获取当前系统已有盘符,进行比较即可。

  1. bool IsDiskExist(char cDiskName)
  2. {
  3. DWORD dwDrivers;
  4. int i = toupper(cDiskName) - 'A';
  5.  
  6. //dwDrivers的每一个二进制位表示对应的驱动器是否存在。
  7. dwDrivers = GetLogicalDrives();
  8. //判断当前位是否有驱动器
  9. if ((dwDrivers & ( << (i))) != )
  10. {
  11. return true;
  12. }
  13. return false;
  14. }

三、获取系统事件

Qt给我们提供了一个QAbstractNativeEventFilter类,该类可以过滤应用程序的所有事件,因此我们的类需要继承并实现此类中的nativeEventFilter方法,在此方法中进行事件过滤,之前写过一个相关的文章qt捕获全局windows消息可以进行参考下,,nativeEventFilter方法想要进行事件过滤,我们必须使用qApp->installNativeEventFilter(this);方法进行注册我们自己写的类。

  1. bool diskoperate::nativeEventFilter( const QByteArray &eventType, void *message, long *result )
  2. {
  3. if ("windows_dispatcher_MSG" == eventType
  4. || "windows_generic_MSG" == eventType)
  5. {
  6. MSG * msg = reinterpret_cast<MSG *>(message);
  7. if(msg->message == WM_DEVICECHANGE)
  8. {
  9. PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
  10. switch(msg->wParam)
  11. {
  12. case DBT_DEVICEARRIVAL://检测到新设备
  13. if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
  14. {
  15. qDebug() << "DBT_DEVICEARRIVAL";
  16. updateMoveDrives();
  17. }
  18. break;
  19. case DBT_DEVICEQUERYREMOVE://请求移除设备,可能失败 此时刷新不会让移动设备消失
  20. if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
  21. {
  22. qDebug() << "DBT_DEVICEQUERYREMOVE";
  23. }
  24. break;
  25. case DBT_DEVICEQUERYREMOVEFAILED://去除中断
  26. if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
  27. {
  28. qDebug() << "DBT_DEVICEQUERYREMOVEFAILED";
  29. }
  30. break;
  31. case DBT_DEVICEREMOVEPENDING://即将删除,仍然有效
  32. if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
  33. {
  34. qDebug() << "DBT_DEVICEREMOVEPENDING";
  35. }
  36. break;
  37. case DBT_DEVICEREMOVECOMPLETE://设备不见了
  38. if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
  39. {
  40. qDebug() << "DBT_DEVICEREMOVECOMPLETE";
  41. updateMoveDrives();
  42. }
  43. break;
  44. case DBT_CUSTOMEVENT:
  45. if (lpdb->dbch_devicetype == DBT_DEVTYP_HANDLE)
  46. {
  47. qDebug() << "DBT_CUSTOMEVENT";
  48. updateMoveDrives();
  49. }
  50. break;
  51. case DBT_DEVNODES_CHANGED:
  52. qDebug() << "DBT_DEVNODES_CHANGED";
  53. updateMoveDrives();
  54. break;
  55. default:
  56. qDebug() << msg->wParam;
  57. }
  58. outputDrives();
  59. }
  60. }
  61.  
  62. return __super::nativeEvent(eventType, message, result);
  63. }

四、运行效果

如下图1所示,一次完整的优盘插入、弹出和删除,所触发的系统事件

图1 测试截图

五、下载连接

  Qt之USB热插拔源码下载实例

相关连接:

1、想用c++写一个监测在win7下的usb插拔监测

2、接收不到DBT_DEVICEQUERYREMOVE消息怎么办?

3、qt捕获全局windows消息

4、USB设备注册与插拔监听

5、mfc检测usb插拔事件

Qt之移动硬盘热插拔监控的更多相关文章

  1. Qt之键盘事件监听-实时响应大小写Capslock按键

    目录 一.开篇 二.效果展示 三.实现思路 1.重写QLlinEdit 2.全局应用程序事件 3.windows钩子 四.相关文章 原文链接:Qt之键盘事件监听-实时响应大小写Capslock按键 一 ...

  2. QT GUI总结

      QT提供了设计师工具,可以很方便的使用鼠标拖拽的方式绘制界面.绘制完毕后自动生成一个界面的.h文件(如ui_mainwindow.h),其中含有一个自动生成的Ui_MainWindow类,这个类中 ...

  3. 我用STM32MP1做了个疫情监控平台4—功能完善界面重新设计

    目录 前言 界面展示 新增功能 API 接口说明 多个接口数据的获取和解析 FontAwesome字体图标库的使用 代码下载 系列教程 @ 前言 之前我用STM32MP1和Qt实现了疫情监控平台,系列 ...

  4. Qt: usb热插拔检测(windows);

    Qt提供了QAbstractNativeEventFilter来实现本地时间得过滤,通过对本地事件的检测,判断usb热插拔:(这里是windows 的例子); 首先,以QWidget, QAbstra ...

  5. 5、Qt Project之键盘数据监控

    键盘数据监控: 同样的,键盘的检测和鼠标的情形很类似,都是以QWidget为基类的工程 Step1:在UI设计中添加该模块需要使用的相关组件,如下所示: <width>141</wi ...

  6. 2、Qt Project之鼠标事件监控

    鼠标事件监控: 对于鼠标时间监控的相关操作,我们在简历工程的时候需要选择的是QWidget基类,不选择QMainWindow基类,如下所示: Base class:QWidget Step1:我们首先 ...

  7. Qt编写视频监控画面分割界面(开源)

    其实qt应用在安防领域还是蛮多的,尤其是视频监控系统,但是网上几乎没有看到qt做的最基础的视频监控画面分割的demo,今天特意花几分钟提取出来,开源放出来.欢迎大家多多点赞!源码下载:点击打开链接 运 ...

  8. Qt编写的RTSP播放器+视频监控(android版本)

    之前写过vlc版本,ffmpeg版本,也在linux上和嵌入式linux上跑过视频监控,这次想直接用ffmpeg的库写个android版本,qt+ffmpeg+android直接用之前的qt+ffmp ...

  9. Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)

    一.自定义控件大全 (一).控件介绍 超过160个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...

随机推荐

  1. enote笔记法(2)——why的使用

    章节:why的使用 用法: why 概念|词汇(比概念更一般的形式的keyword)|短语|句子 用法1: why 概念|why keyword([比概念更一般的形式的keyword]) “why 概 ...

  2. python基础教程——函数

    定义函数 //abstest.py def my_abs(x): if x >= 0: return x else: return -x 在该文件的当前目录下启动python解释器,用 from ...

  3. [译]漫画SELinux概念

    h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...

  4. caioj 1236 最近公共祖先 树倍增算法模版 倍增

    [题目链接:http://caioj.cn/problem.php?id=1236][40eebe4d] 代码:(时间复杂度:nlogn) #include <iostream> #inc ...

  5. php加密字符串超时不可解密

    <?php/** * 加密字符串在指定时间内解密有效 * @param  [type]  $string    明文字符串 * @param  string  $operation 解密值为DE ...

  6. Android ListView与RecycleView的对比使用

    ListView,就如其名,是用来显示列表的一种View,而RecycleView,是其的加强版,今天带来的是这两个几乎具有相同的功能的对比使用 先从ListView说起吧 ListView: 1.在 ...

  7. Jarvis OJ - [XMAN]level3 - Writeup——ret2libc尝试

    这次除了elf程序还附带一个动态链接库 先看一下,很一般的保护 思路分析 在ida中查看,可以确定通过read函数输入buf进行溢出,但是并没有看到合适的目标函数 但是用ida打开附带的链接库,可以看 ...

  8. google开源服务器apprtc的搭建

    本文参考网帖: http://www.jianshu.com/p/c55ecf5a3fcf http://io.diveinedu.com/2015/02/05/%E7%AC%AC%E5%85%AD% ...

  9. C++ vector 常用API

    vector: 向量容器,动态数组,类模板 定义和初始化: vector<T> v1; //v1是空vector,元素类型是T类型,执行默认初始化,int为0,string为空串 vect ...

  10. python 3.6 tkinter+urllib+json 火车车次信息查询

    --------blogs:  陈月白    http://www.cnblogs.com/chenyuebai    -------- 一.概述 妹子工作时需要大量地查询火车车次至南京的信息,包括该 ...