参考腾讯电脑管家-软件市场中的驱动备份专家写的一个驱动备份软件案例,学习Setupapi.h库中的函数使用.通过Setupapi.h库读取设备管理器中安装的设备获取安装的驱动列表,通过bit7z库备份驱动目录下的所有文件.
目录导读
-
- 实现效果
- 相关内容示例
-
- 获取SP_DRVINFO_DETAIL_DATA结构数据
- 相关函数
-
- [SetupDiBuildDriverInfoList 函数](#SetupDiBuildDriverInfoList 函数)
- SetupDiEnumDriverInfo函数
- [SetupDiGetDriverInfoDetail 函数](#SetupDiGetDriverInfoDetail 函数)
- 相关实现
-
- 获取所有驱动列表
- 获取驱动SP_DRVINFO_DETAIL_DATA结构数据
- [qDebug打印输出 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结构包含有关特定驱动程序信息结构的详细信息。
语法
cpp
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 函数生成与特定设备关联的驱动程序列表,或与设备信息集的全局类驱动程序列表相关联。
语法
cpp
//! 如果成功,该函数将返回 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 函数枚举驱动程序列表的成员。
语法
cpp
//! 如果成功,该函数将返回 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 函数检索设备信息集或设备信息集中特定设备信息元素的驱动程序信息详细信息。
语法
cpp
//! 如果成功,该函数将返回 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 列表的末尾的可变长度字符缓冲区所需的其他字节。
);
相关实现
获取所有驱动列表
cpp
//! 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异常
cpp
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
cpp
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 exists
if (rDriverInfoDetail->CompatIDsOffset > 1)
{
// Parse for hardware ID from index 0.
// This is a single NULL-terminated string
qDebug()<<"设备的硬件 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 exist
if (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;
}