Qt案例 通过调用Setupapi.h库实现对设备管理器中设备默认驱动的备份

2024-04-09 11:20

本文主要是介绍Qt案例 通过调用Setupapi.h库实现对设备管理器中设备默认驱动的备份,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考腾讯电脑管家-软件市场中的驱动备份专家写的一个驱动备份软件案例,学习Setupapi.h库中的函数使用.通过Setupapi.h库读取设备管理器中安装的设备获取安装的驱动列表,通过bit7z库备份驱动目录下的所有文件.

目录导读

    • 实现效果
    • 相关内容示例
      • 获取SP_DRVINFO_DETAIL_DATA结构数据
      • 相关函数
        • SetupDiBuildDriverInfoList 函数
        • SetupDiEnumDriverInfo函数
        • SetupDiGetDriverInfoDetail 函数
      • 相关实现
        • 获取所有驱动列表
        • 获取驱动SP_DRVINFO_DETAIL_DATA结构数据
        • qDebug打印输出 SP_DRVINFO_DETAIL_DATA 结构数据

实现效果

参考腾讯电脑管家-软件市场中的驱动备份专家软件
在这里插入图片描述
实现对设备管理器中的驱动信息的读取和备份:
在这里插入图片描述
其中的驱动名称,版本信息和驱动目录都是通过设备管理器的属性获取,
详情参考以下文章内容:
Qt案例 调用WINDOWS API中的SETUPAPI.H库获取设备管理器中设备的详细信息中的属性值(一)
Qt案例 调用WINDOWS API中的SETUPAPI.H库获取设备管理器中设备的详细信息中的属性值(二)
驱动备份使用bit7z调用7z.exe实现相关功能,参考:
Qt 编译使用Bit7z库接口调用7z.dll、7-Zip.dll解压压缩常用Zip、ISO9660、Wim、Esd、7z等格式文件(一)

相关内容示例

遍历设备管理器中驱动程序的相关信息:

  • 获取SP_DRVINFO_DETAIL_DATA结构数据

SP_DRVINFO_DETAIL_DATA结构包含有关特定驱动程序信息结构的详细信息。
语法

typedef struct _SP_DRVINFO_DETAIL_DATA_W {DWORD     cbSize;  //SP_DRVINFO_DETAIL_DATA结构的大小(以字节为单位)。FILETIME  InfDate; //此驱动程序的 INF 文件的日期。DWORD     CompatIDsOffset; //此值还可用于确定 CompatID 列表之前是否有 硬件 ID 。 如果此值大于 1,则 HardwareID 缓冲区中的第一个字符串是硬件 ID。 如果此值小于或等于 1,则没有硬件 ID。DWORD     CompatIDsLength; //CompatID 列表的长度(以字符为单位),从 HardwareID 缓冲区的开头偏移 CompatIDsOffset 开始。ULONG_PTR Reserved; //保留。 仅限内部使用。WCHAR     SectionName[LINE_LEN]; //一个以 NULL 结尾的字符串,包含此驱动程序的 INF DDInstall 节 的名称。 这必须是基本 DDInstall 节名称(如 InstallSec),没有任何特定于 OS/体系结构的扩展。WCHAR     InfFileName[MAX_PATH]; //一个以 NULL 结尾的字符串,其中包含此驱动程序的 INF 文件的完整限定名称。WCHAR     DrvDescription[LINE_LEN]; //一个以 NULL 结尾的字符串,用于描述驱动程序。WCHAR     HardwareID[ANYSIZE_ARRAY]; //包含 ID 列表的缓冲区 (单个 硬件 ID ,后跟 兼容 ID 列表) 。 这些 ID 对应于 INF 模型部分中的硬件 ID 和兼容 ID。列表中的每个 ID 都是以 NULL 结尾的字符串。
} SP_DRVINFO_DETAIL_DATA_W, *PSP_DRVINFO_DETAIL_DATA_W;

相关函数

  • SetupDiBuildDriverInfoList 函数

SetupDiBuildDriverInfoList 函数生成与特定设备关联的驱动程序列表,或与设备信息集的全局类驱动程序列表相关联。
语法

//! 如果成功,该函数将返回 TRUE 。 否则,它将返回 FALSE ,并且可以通过调用 GetLastError 来检索记录的错误。
WINSETUPAPI BOOL SetupDiBuildDriverInfoList([in]      HDEVINFO         DeviceInfoSet,  //设备信息设置为包含驱动程序列表的设备信息的句柄,可以是全局所有设备信息元素,也可以是专用于单个设备信息元素。 设备信息集不得包含远程设备信息元素[in, out] PSP_DEVINFO_DATA DeviceInfoData,//指向 DeviceInfoSet 中设备信息元素的SP_DEVINFO_DATA结构的指针,该元素表示要为其生成驱动程序列表的设备。 此参数是可选的,可以为 NULL。 如果指定此参数,则列表与指定的设备相关联。 如果此参数为 NULL,则列表与 DeviceInfoSet 的全局类驱动程序列表相关联。[in]      DWORD            DriverType //要生成的驱动程序列表的类型
);
  • SetupDiEnumDriverInfo函数

SetupDiEnumDriverInfo 函数枚举驱动程序列表的成员。
语法

//! 如果成功,该函数将返回 TRUE 。 否则,它将返回 FALSE ,并且可以通过调用 GetLastError 来检索记录的错误。
WINSETUPAPI BOOL SetupDiEnumDriverInfoA([in]           HDEVINFO           DeviceInfoSet, //包含要枚举的驱动程序列表 的设备信息集 的句柄。[in, optional] PSP_DEVINFO_DATA   DeviceInfoData, //指向 SP_DEVINFO_DATA 结构的指针,该结构指定 DeviceInfoSet 中的设备信息元素。 此参数是可选的,可以为 NULL。 如果指定此参数, SetupDiEnumDriverInfo 将枚举指定设备的驱动程序列表。 如果此参数为 NULL, 则 SetupDiEnumDriverInfo 枚举与 DeviceInfoSet 关联的全局类驱动程序列表, (此列表的类型为 SPDIT_CLASSDRIVER) 。[in]           DWORD              DriverType, //要枚举的驱动程序列表的类型[in]           DWORD              MemberIndex, //要检索的驱动程序信息成员的从零开始的索引。[out]          PSP_DRVINFO_DATA_A DriverInfoData //指向调用方初始化 的SP_DRVINFO_DATA 结构的指针,该结构接收有关枚举驱动程序的信息。 调用方必须设置 DriverInfoData。在调用 SetupDiEnumDriverInfo 之前,cbSize 为 sizeof ( SP_DRVINFO_DATA) 。 如果未正确设置 cbSize 成员, 则 SetupDiEnumDriverInfo 将返回 FALSE。
);
  • SetupDiGetDriverInfoDetail 函数

SetupDiGetDriverInfoDetail 函数检索设备信息集或设备信息集中特定设备信息元素的驱动程序信息详细信息。
语法

//! 如果成功,该函数将返回 TRUE 。 否则,它将返回 FALSE 
WINSETUPAPI BOOL SetupDiGetDriverInfoDetailW([in]            HDEVINFO                  DeviceInfoSet, //包含要为其检索驱动程序信息的驱动程序信息元素 的设备信息集 的句柄。[in, optional]  PSP_DEVINFO_DATA          DeviceInfoData, //指向 SP_DEVINFO_DATA 结构的指针,该结构指定表示要为其检索驱动程序信息的设备的设备信息元素。 此参数是可选的,可以为 NULL。 如果指定此参数, SetupDiGetDriverInfoDetail 将检索指定设备的驱动程序列表中有关驱动程序的信息。 如果此参数为 NULL, 则 SetupDiGetDriverInfoDetail 将检索有关作为 DeviceInfoSet 全局类驱动程序列表成员的驱动程序的信息。[in]            PSP_DRVINFO_DATA_W        DriverInfoData, //指向 SP_DRVINFO_DATA 结构的指针,该结构指定要为其检索详细信息的驱动程序信息元素。 如果指定 了 DeviceInfoData ,则驱动程序必须是 DeviceInfoData 指定的设备的驱动程序列表的成员。 否则,驱动程序必须是 DeviceInfoSet 的全局类驱动程序列表的成员。[in, out]       PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData, //指向 SP_DRVINFO_DETAIL_DATA 结构的指针,该结构接收有关指定驱动程序的详细信息。 如果未指定此参数, DriverInfoDetailDataSize 必须为零。 如果指定此参数,则 DriverInfoDetailData。在调用 SetupDiGetDriverInfoDetail 之前,cbSize 必须设置为 size of ( SP_DRVINFO_DETAIL_DATA) 的值。[in]            DWORD                     DriverInfoDetailDataSize, //DriverInfoDetailData 缓冲区的大小(以字节为单位)。[out, optional] PDWORD                    RequiredSize //向变量的指针,该变量接收存储详细驱动程序信息所需的字节数。 此值包括结构的大小,以及包含硬件 ID 列表和兼容 ID 列表的末尾的可变长度字符缓冲区所需的其他字节。
);

相关实现

获取所有驱动列表
//! QList<CONST GUID*> GUID_DEVCLASS_LIST 设备标识
for(int t=0;t<GUID_DEVCLASS_LIST.count();t++){QString IconPath=Lib_ExtrationDrives::getInstance().GeticonPath(GUID_DEVCLASS_LIST[t]);HDEVINFO deviceInfoSet = SetupDiGetClassDevs(GUID_DEVCLASS_LIST[t], NULL, NULL, DIGCF_PRESENT);if (deviceInfoSet == INVALID_HANDLE_VALUE) {printf("Failed to get device information set. Error code: %d\n", GetLastError());return ;}SP_DEVINFO_DATA deviceInfoData;deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoSet, i, &deviceInfoData); i++) {//SetupDiBuildDriverInfoList 函数生成与特定设备关联的驱动程序列表,或与设备信息集的全局类驱动程序列表相关联。bool ret = SetupDiBuildDriverInfoList(deviceInfoSet, &deviceInfoData, SPDIT_CLASSDRIVER);if(!ret){qDebug("Error enumerating driver info. Error code: %d\n", GetLastError());continue ;}SP_DRVINFO_DATA  rDriverInfoData;rDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);//SetupDiEnumDriverInfo 函数枚举驱动程序列表的成员for(int j=0;SetupDiEnumDriverInfo(deviceInfoSet, &deviceInfoData, SPDIT_CLASSDRIVER, j, &rDriverInfoData);j++){PSP_DRVINFO_DETAIL_DATA rDriverInfoDetail=new SP_DRVINFO_DETAIL_DATA() ;rDriverInfoDetail->cbSize=sizeof(SP_DRVINFO_DETAIL_DATA);if(Lib_ExtrationDrives::getInstance().GetSetupDiGetDriverInfoDetail(deviceInfoSet,&deviceInfoData, &rDriverInfoData,rDriverInfoDetail)){qDebug()<<"-----"<<i<<" - "<<j;
//                    Print_DriverInfoDetail(rDriverInfoDetail);qDebug()<<"[cbSize] :"<<rDriverInfoDetail->cbSize;qDebug()<<"[SectionName] :"<<QString::fromWCharArray(rDriverInfoDetail->SectionName);//! SetupOpenInfFile 函数打开一个 INF 文件并返回它的句柄。qDebug()<<"[InfFileName] :"<<QString::fromWCharArray(rDriverInfoDetail->InfFileName);qDebug()<<"[DrvDescription] :"<<QString::fromWCharArray(rDriverInfoDetail->DrvDescription);qDebug()<<"[CompatIDsOffset] :"<<rDriverInfoDetail->CompatIDsOffset;qDebug()<<"[CompatIDsLength] :"<<rDriverInfoDetail->CompatIDsLength;}free(rDriverInfoDetail);}}SetupDiDestroyDeviceInfoList(deviceInfoSet);}
获取驱动SP_DRVINFO_DETAIL_DATA结构数据

通过SetupDiGetDriverInfoDetail函数检索SP_DRVINFO_DETAIL_DATA包含有关特定驱动程序信息结构的详细信息,预防ERROR_INSUFFICIENT_BUFFER异常

bool Lib_ExtrationDrives::GetSetupDiGetDriverInfoDetail(HDEVINFO infoset,PSP_DEVINFO_DATA device,PSP_DRVINFO_DATA  rDriver,PSP_DRVINFO_DETAIL_DATA& rDriverInfoDetail) const
{bool isSuccess=true;DWORD needSize=0;if(!SetupDiGetDriverInfoDetail(infoset,device,rDriver,rDriverInfoDetail,sizeof(SP_DRVINFO_DETAIL_DATA),&needSize)){if((GetLastError()== ERROR_INSUFFICIENT_BUFFER)){//                qDebug()<<"cbSize : "<<rDriverInfoDetail->cbSize<<" needSize : "<<needSize;rDriverInfoDetail=(SP_DRVINFO_DETAIL_DATA*)malloc(needSize);rDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA)  ;if (!SetupDiGetDriverInfoDetail(infoset, device, rDriver, rDriverInfoDetail, needSize, NULL)){isSuccess=false;qDebug()<<"Error getting detailed driver info . because needSize:"<<needSize;}}else{isSuccess=false;qDebug()<<"Error getting detailed driver info !";}}return isSuccess;
}
qDebug打印输出 SP_DRVINFO_DETAIL_DATA 结构数据

注:根据硬件 ID 和 兼容 ID 列表在 INF 模型部分中的指定方式, HardwareID 缓冲区可以类似于以下任何一种:

  • \0
  • <HWID>\0
  • <HWID>\0<COMPATID_1>\0…<COMPATID_N>\0\0
  • \0<COMPATID_1>\0…<>COMPATID_N\0\0
void Print_DriverInfoDetail(PSP_DRVINFO_DETAIL_DATA rDriverInfoDetail) 
{qDebug()<<"[cbSize] :"<<rDriverInfoDetail->cbSize;qDebug()<<"[SectionName] :"<<QString::fromWCharArray(rDriverInfoDetail->SectionName);//! SetupOpenInfFile 函数打开一个 INF 文件并返回它的句柄。qDebug()<<"[InfFileName] :"<<QString::fromWCharArray(rDriverInfoDetail->InfFileName);qDebug()<<"[DrvDescription] :"<<QString::fromWCharArray(rDriverInfoDetail->DrvDescription);qDebug()<<"[CompatIDsOffset] :"<<rDriverInfoDetail->CompatIDsOffset;qDebug()<<"[CompatIDsLength] :"<<rDriverInfoDetail->CompatIDsLength;// parse the hardware ID, if it existsif (rDriverInfoDetail->CompatIDsOffset > 1){// Parse for hardware ID from index 0.// This is a single NULL-terminated stringqDebug()<<"设备的硬件 id:";//            qDebug()<<QString::fromWCharArray(rDriverInfoDetail->HardwareID);wchar_t* hardwareid=new wchar_t[MAX_PATH];int col=0;for(int i=0;i<rDriverInfoDetail->CompatIDsOffset;i++){if(rDriverInfoDetail->HardwareID[i]!='\0'){hardwareid[col]=rDriverInfoDetail->HardwareID[i];col++;}else{hardwareid[col]='\0';qDebug()<<QString::fromWCharArray(hardwareid);free(hardwareid);hardwareid=new wchar_t[MAX_PATH];col=0;}}}// Parse the compatible IDs, if they existif (rDriverInfoDetail->CompatIDsLength > 0){qDebug()<<"设备的兼容 id:";// Parse for list of compatible IDs from CompatIDsOffset.// This is a double NULL-terminated list of strings (i.e. MULTI-SZ)wchar_t* compatibleid=new wchar_t[MAX_PATH];int col=0;int lengths=rDriverInfoDetail->CompatIDsOffset+rDriverInfoDetail->CompatIDsLength;for(int i=rDriverInfoDetail->CompatIDsOffset;i<lengths;i++){if(rDriverInfoDetail->HardwareID[i]!='\0'){compatibleid[col]=rDriverInfoDetail->HardwareID[i];col++;}else{compatibleid[col]='\0';qDebug()<<QString::fromWCharArray(compatibleid);free(compatibleid);if(i+1<lengths &&(rDriverInfoDetail->HardwareID[i+1]=='\0')) //结束break;compatibleid=new wchar_t[MAX_PATH];col=0;}}}qDebug()<<endl;}

这篇关于Qt案例 通过调用Setupapi.h库实现对设备管理器中设备默认驱动的备份的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time