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 中 isHidden 和 isVisible 的区别与使用小结

《Qt中isHidden和isVisible的区别与使用小结》Qt中的isHidden()和isVisible()方法都用于查询组件显示或隐藏状态,然而,它们有很大的区别,了解它们对于正确操... 目录1. 基础概念2. 区别清见3. 实际案例4. 注意事项5. 总结1. 基础概念Qt 中的 isHidd

QT移植到RK3568开发板的方法步骤

《QT移植到RK3568开发板的方法步骤》本文主要介绍了QT移植到RK3568开发板的方法步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录前言一、获取SDK1. 安装依赖2. 获取SDK资源包3. SDK工程目录介绍4. 获取补丁包二

Qt把文件夹从A移动到B的实现示例

《Qt把文件夹从A移动到B的实现示例》本文主要介绍了Qt把文件夹从A移动到B的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录如何移动一个文件? 如何移动文件夹(包含里面的全部内容):如何删除文件夹:QT 文件复制,移动(

Qt实现发送HTTP请求的示例详解

《Qt实现发送HTTP请求的示例详解》这篇文章主要为大家详细介绍了如何通过Qt实现发送HTTP请求,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、添加network模块2、包含改头文件3、创建网络访问管理器4、创建接口5、创建网络请求对象6、创建一个回复对

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

使用zabbix进行监控网络设备流量

《使用zabbix进行监控网络设备流量》这篇文章主要为大家详细介绍了如何使用zabbix进行监控网络设备流量,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录安装zabbix配置ENSP环境配置zabbix实行监控交换机测试一台liunx服务器,这里使用的为Ubuntu22.04(

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用