我是靠谱客的博主 勤奋睫毛,最近开发中收集的这篇文章主要介绍获取电脑硬件对应的驱动程序信息,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

刚换了工作,入职时候大佬让我研究下 驱动人生/驱动精灵 判断驱动是否正常是怎么做到的

一开始是一脸懵逼的,完全不知道要如何下手,不过应该是获取设备管理器里硬件属性,然后进行判断吧,我就跟据我的猜测进行研究。

第一个要解决的问题就是要如何获得设备管理器上的信息
在MSDN游荡了很久,发现了

CMAPI
CONFIGRET
WINAPI CM_Enumerate_Classes(
  _In_  ULONG  ulClassIndex,
  _Out_ LPGUID ClassGuid,
  _In_  ULONG  ulFlags
);

The CM_Enumerate_Classes function, when called repeatedly, enumerates the local machine’s installed device classes by supplying each class’s GUID.

这函数的功能就是枚举本地机器上安装的每个设备类的GUID。(我的理解:每个设备类里面就有很多具体的设备,就类似一棵树的根,下面会有很多子节点。至于归类方式,微软说是以设备的安装方式来归类的,具体参看MSDN:Device Classes)

获得了设备类的GUID,那应该有遍历这个设备类里每个设备的函数,我就继续在MSDN游荡。。。终于发现了另一个函数,

HDEVINFO SetupDiGetClassDevs(
  _In_opt_ const GUID   *ClassGuid,
  _In_opt_       PCTSTR Enumerator,
  _In_opt_       HWND   hwndParent,
  _In_           DWORD  Flags
);

The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local computer.

这个函数的功能就是能返回包含本地计算机上相应请求的信息。(我刚开始并不知道这个鬼玩意能干啥,跟上一个CM_*函数也不一样,就看到第一个参数是GUID,就抱着试一试的态度用了下。)

在该函数的MSDN文档中,有示例用法,提到了另一个函数:

BOOL SetupDiEnumDeviceInfo(
  _In_  HDEVINFO         DeviceInfoSet,
  _In_  DWORD            MemberIndex,
  _Out_ PSP_DEVINFO_DATA DeviceInfoData
);

The SetupDiEnumDeviceInfo function returns a SP_DEVINFO_DATA structure that specifies a device information element in a device information set.

看样子就是一个用来遍历的函数。这个函数返回指定信息集中指定元素的信息。感觉看到了希望。。。

然后又找到一个函数:

BOOL SetupDiGetDeviceRegistryProperty(
  _In_      HDEVINFO         DeviceInfoSet,
  _In_      PSP_DEVINFO_DATA DeviceInfoData,
  _In_      DWORD            Property,
  _Out_opt_ PDWORD           PropertyRegDataType,
  _Out_opt_ PBYTE            PropertyBuffer,
  _In_      DWORD            PropertyBufferSize,
  _Out_opt_ PDWORD           RequiredSize
);

The SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play device property.

这个函数负责检索指定即插即用设备示例属性。(有的设备并不是即插即用,所以估计会有问题,有一个函数SetupDiGetDeviceProperty 是获得设备的实例属性,但是参数研究了半天也不知道怎么填。)

这个函数的第三个参数设置了要获取的内容:
我就用了SPDRP_DEVICEDESCSPDRP_HARDWAREID 分别是获得设备名称和设备的硬件ID。

##找到了具体的硬件,接下来是找对应的驱动
在获取驱动之前,需要先用SetupDiBuildDriverInfoList 创建驱动信息列表。

BOOL SetupDiBuildDriverInfoList(
  _In_    HDEVINFO         DeviceInfoSet,
  _Inout_ PSP_DEVINFO_DATA DeviceInfoData,
  _In_    DWORD            DriverType
);

The SetupDiBuildDriverInfoList function builds a list of drivers that is associated with a specific device or with the global class driver list for a device information set.

这个函数负责收集对应设备类的驱动,前两个参数起到确定硬件的作用,第一个参数是硬件信息集,是SetupDiGetClassDevs 函数返回的,就是确定是哪一类设备;第二个参数是设备信息,这个参数是SetupDiEnumDeviceInfo 返回的,确定具体是哪一个设备;第三个设备则是确定要生成的驱动信息列表是要对应设备类的所有驱动还是对应设备类中某个设备的驱动。

收集完驱动信息后就可以遍历驱动信息了:

BOOL SetupDiEnumDriverInfo(
  _In_      HDEVINFO DeviceInfoSet,
  _In_opt_  PSP_DEVINFO_DATA DeviceInfoData,
  _In_      DWORD DriverType,
  _In_      DWORD MemberIndex,
  _Out_     PSP_DRVINFO_DATA_W DriverInfoData
);

The SetupDiEnumDriverInfo function enumerates the members of a driver list.

这个函数负责遍历SetupDiBuildDriverInfoList 生成的驱动列表。

##由此,获得对应设备的驱动信息的功能已经实现
Windows中获取驱动的流程基本是这样:首先拿到设备类,然后遍历设备类中的设备(在本机上安装的设备),然后获取对应设备的驱动程序。

驱动人生驱动精灵 识别硬件并确定驱动是否最优我猜应该是有一个自己的数据库,根据硬件的硬件ID进行匹配。

#如果我哪里分析得不对希望大佬留言指正。

Demo(VS2015上编译通过):

#include <Windows.h>
#include <Cfgmgr32.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <SetupAPI.h>
#include <tchar.h>

#pragma comment(lib, "Cfgmgr32.lib")
#pragma comment(lib, "Setupapi.lib")

using namespace std;

void printGUID(GUID& guid);
TCHAR* FindVersionFromULONGLONG(ULONGLONG data);

int main()
{
	GUID guid = { 0 };
	DWORD dwRet = 0;
	ULONG guidIndex = 0;

	setlocale(LC_ALL, "chs");//让程序支持UTF-16中文的输出

	while (true)
	{
		dwRet = CM_Enumerate_Classes(guidIndex++, &guid, 0);
		if (CR_NO_SUCH_VALUE == dwRet)
		{
			cout << "设备类枚举完成" << endl;
			break;
		}
		printGUID(guid);

		HDEVINFO hdevInfo = 0;
		hdevInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT);
		if (INVALID_HANDLE_VALUE == hdevInfo)
		{
			cout << "SetupDiGetClassDevs failed" << endl;
			break;
		}

		DWORD deviceIndex = 0;
		SP_DEVINFO_DATA devInfoData = { sizeof(SP_DEVINFO_DATA) };

		for (deviceIndex = 0; SetupDiEnumDeviceInfo(hdevInfo, deviceIndex, &devInfoData);++deviceIndex)
		{
			_tprintf(L"-------------------------------------------------------------n现有设备:n");
			
			ULONG buffSize = 0;
			if (CR_SUCCESS != CM_Get_Device_ID_Size(&buffSize, devInfoData.DevInst, 0))
			{
				break;
			}

			TCHAR* buff = new TCHAR[buffSize + 1];
			dwRet = CM_Get_Device_ID(devInfoData.DevInst, buff, buffSize, 0);
			if (CR_SUCCESS != dwRet)
			{
				break;
			}
			buff[buffSize] = TEXT('');
			_tprintf(TEXT("Device ID:%sn"), buff);
			delete[]buff;

			DWORD dwPropertyRegDataType, dwSize;
			wchar_t propertyBuffer[4096];
			
			if (SetupDiGetDeviceRegistryProperty(hdevInfo, &devInfoData, SPDRP_DEVICEDESC,
				&dwPropertyRegDataType, (PBYTE)propertyBuffer, sizeof(propertyBuffer), &dwSize))
			{
				_tprintf(L"Device Name:%sn", propertyBuffer);
			}

			
			if (SetupDiGetDeviceRegistryProperty(hdevInfo, &devInfoData, SPDRP_HARDWAREID,
				&dwPropertyRegDataType, (PBYTE)propertyBuffer, sizeof(propertyBuffer), &dwSize))
			{
				_tprintf(L"硬件ID:n");
				wchar_t* p = propertyBuffer;
				for (; *p != TEXT('') && p + dwSize / sizeof(char) <= propertyBuffer + ARRAYSIZE(propertyBuffer); p += lstrlen(p) + 1)
				{
					_tprintf(L"%sn", p);
				}
			}
			else
			{
				continue;
			}

			_tprintf(L"n兼容ID:n");
			if (SetupDiGetDeviceRegistryProperty(hdevInfo, &devInfoData, SPDRP_COMPATIBLEIDS,
				&dwPropertyRegDataType, (PBYTE)propertyBuffer, sizeof(propertyBuffer), &dwSize))
			{
				wchar_t* p = propertyBuffer;
				for (; *p != TEXT('') && p + dwSize / sizeof(char) <= propertyBuffer + ARRAYSIZE(propertyBuffer); p += lstrlen(p) + 1)
				{
					_tprintf(TEXT("%sn"), p);
				}
			}

			_tprintf(TEXT("n对应驱动:n"));
			//遍历驱动
			if (SetupDiBuildDriverInfoList(hdevInfo, &devInfoData, SPDIT_COMPATDRIVER))
			{
				SP_DRVINFO_DATA driverInfoData = { sizeof(SP_DRVINFO_DATA) };
				int i = 0;
				for (; SetupDiEnumDriverInfo(hdevInfo, &devInfoData, SPDIT_COMPATDRIVER, i, &driverInfoData); ++i);

				--i;
				_tprintf(TEXT("设备名称:%sn"), driverInfoData.Description);
				_tprintf(TEXT("驱动程序提供商:%sn"), driverInfoData.ProviderName);
				_tprintf(TEXT("设备制造商:%sn"), driverInfoData.MfgName);
				_tprintf(TEXT("驱动程序版本:%sn"), FindVersionFromULONGLONG(driverInfoData.DriverVersion));

				SYSTEMTIME sysTime;
				FileTimeToSystemTime(&driverInfoData.DriverDate, &sysTime);
				_tprintf(TEXT("驱动程序日期:%d/%d/%dn"),
					sysTime.wYear, sysTime.wMonth, sysTime.wDay);
				
				SetupDiDestroyDriverInfoList(hdevInfo, &devInfoData, SPDIT_COMPATDRIVER);
			}
			else
			{
				_tprintf(TEXT("n没找到对应驱动程序n"));
			}
			_tprintf(TEXT("-------------------------------------------------------------n"));
		}
	}

	system("pause");
    return 0;
}

void printGUID(GUID& guid)
{
	_tprintf(TEXT("GUID:%8X %4X %4X %2X %2X %2X %2X %2X %2X %2X %2Xn"),
		guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], 
		guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}

TCHAR* FindVersionFromULONGLONG(ULONGLONG data)
{
	static TCHAR buff[64];
	memset(buff, 0, sizeof(buff));
	ULONG temp = 0;
	TCHAR numbuff[8];

	for (int i = 48; i >= 0; i -= 16)
	{
		temp = (data >> i) & 0xFFFF;
		_ultot_s(temp, numbuff, 10);
		_tcscat_s(buff, numbuff);
		_tcscat_s(buff, TEXT("."));
	}
	buff[_tcslen(buff) - 1] = 0;
	return buff;
}

最后

以上就是勤奋睫毛为你收集整理的获取电脑硬件对应的驱动程序信息的全部内容,希望文章能够帮你解决获取电脑硬件对应的驱动程序信息所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部