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 Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

springboot2.1.3 hystrix集成及hystrix-dashboard监控详解

《springboot2.1.3hystrix集成及hystrix-dashboard监控详解》Hystrix是Netflix开源的微服务容错工具,通过线程池隔离和熔断机制防止服务崩溃,支持降级、监... 目录Hystrix是Netflix开源技术www.chinasem.cn栈中的又一员猛将Hystrix熔

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

一文解密Python进行监控进程的黑科技

《一文解密Python进行监控进程的黑科技》在计算机系统管理和应用性能优化中,监控进程的CPU、内存和IO使用率是非常重要的任务,下面我们就来讲讲如何Python写一个简单使用的监控进程的工具吧... 目录准备工作监控CPU使用率监控内存使用率监控IO使用率小工具代码整合在计算机系统管理和应用性能优化中,监

Zabbix在MySQL性能监控方面的运用及最佳实践记录

《Zabbix在MySQL性能监控方面的运用及最佳实践记录》Zabbix通过自定义脚本和内置模板监控MySQL核心指标(连接、查询、资源、复制),支持自动发现多实例及告警通知,结合可视化仪表盘,可有效... 目录一、核心监控指标及配置1. 关键监控指标示例2. 配置方法二、自动发现与多实例管理1. 实践步骤

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

如何在Ubuntu 24.04上部署Zabbix 7.0对服务器进行监控

《如何在Ubuntu24.04上部署Zabbix7.0对服务器进行监控》在Ubuntu24.04上部署Zabbix7.0监控阿里云ECS服务器,需配置MariaDB数据库、开放10050/1005... 目录软硬件信息部署步骤步骤 1:安装并配置mariadb步骤 2:安装Zabbix 7.0 Server