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

相关文章

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

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、创建一个回复对