Qt之移动硬盘热插拔监控

2024-02-07 03:20

本文主要是介绍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个,如下表所示

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(0).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         0,
14         OPEN_EXISTING,
15         FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
16         0);//拿到盘符句柄
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(0)] = 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 & (1 << (i))) != 0)  
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 }
View Code

四、运行效果

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

图1 测试截图

 

五、下载连接

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

 

相关连接:

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

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

3、qt捕获全局windows消息

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

5、mfc检测usb插拔事件

转载于:https://www.cnblogs.com/swarmbees/p/8145342.html

这篇关于Qt之移动硬盘热插拔监控的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/686367

相关文章

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

Qt如何实现文本编辑器光标高亮技术

《Qt如何实现文本编辑器光标高亮技术》这篇文章主要为大家详细介绍了Qt如何实现文本编辑器光标高亮技术,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录实现代码函数作用概述代码详解 + 注释使用 QTextEdit 的高亮技术(重点)总结用到的关键技术点应用场景举例示例优化建议

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

VS配置好Qt环境之后但无法打开ui界面的问题解决

《VS配置好Qt环境之后但无法打开ui界面的问题解决》本文主要介绍了VS配置好Qt环境之后但无法打开ui界面的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目UKeLvb录找到Qt安装目录中designer.UKeLvBexe的路径找到vs中的解决方案资源

JVisualVM之Java性能监控与调优利器详解

《JVisualVM之Java性能监控与调优利器详解》本文将详细介绍JVisualVM的使用方法,并结合实际案例展示如何利用它进行性能调优,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1. JVisualVM简介2. JVisualVM的安装与启动2.1 启动JVisualVM2

Qt之QMessageBox的具体使用

《Qt之QMessageBox的具体使用》本文介绍Qt中QMessageBox类的使用,用于弹出提示、警告、错误等模态对话框,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.简单介绍3.常见函数4.按钮类型(QMessage::StandardButton)5.分步骤实现弹窗6.总结1.引言

Qt中Qfile类的使用

《Qt中Qfile类的使用》很多应用程序都具备操作文件的能力,包括对文件进行写入和读取,创建和删除文件,本文主要介绍了Qt中Qfile类的使用,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.QFile文件操作3.演示示例3.1实验一3.2实验二【演示 QFile 读写二进制文件的过程】4.

使用Python实现实时金价监控并自动提醒功能

《使用Python实现实时金价监控并自动提醒功能》在日常投资中,很多朋友喜欢在一些平台买点黄金,低买高卖赚点小差价,但黄金价格实时波动频繁,总是盯着手机太累了,于是我用Python写了一个实时金价监控... 目录工具能干啥?手把手教你用1、先装好这些"食材"2、代码实现讲解1. 用户输入参数2. 设置无头浏

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义