ACTK实现:SetupDi 获得设备列表

SetupDi 函数(主要介绍输出设备列表使用到的函数)

包含头文件和库

#include <SetupAPI.h>
#pragma comment(lib,"SetupAPI.lib")
【第一】SetupDiGetClassDevs

【函数说明】:获取一个指定类别(如全部的麦克风)或全部类别的所以已安装设备的信息的句柄
【函数原型】:

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

【参数说明】:

  • ClassGuid : 一个特定类别GUID的指针(可以通过设备管理查询)
  • Enumerator : 过滤枚举的内容:如:PCI则只显示PCI设备,
  • hwndParent : 用于关联到集合成员中的用户接口的顶层窗口句柄
  • Flags : 建立设备信息表的控制选项,可以是下列值
    • NULL,将返回 guid 指定的设备信息句柄
    • DIGCF_ALLCLASSES范围最广:对全部的任何设备类或接口类有支持的设备;此参数将忽略 ClassGuid,将返回所有类别的设备信息表
    • DIGCF_DEVICEINTERFACE:仅包含支持设备接口类的设备;
    • DIGCF_DEFAULT:仅包含支持默认接口类的设备;
    • DIGCF_PRESENT:当前连接的设备;
    • DIGCF_PROFILE:Hardware Profile中的设备,要看哪些设备在硬件Profile中,应到注册表键HKLM/SYSTEM/CurrentControlSet/Hardware Profiles/Current/System/CurrentControlSet下查看。

【返回值】
如成功,返回包含所有与指定参数匹配的已经安装设备信息句柄
如失败则返回 INVALID_HANDLE_VALUE

【第二】SetupDiEnumDeviceInfo

【函数原型】

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

【函数说明】
根据SetupDiGetClassDevs返回的设备信息句柄,枚举指定设备信息集合的成员,并将数据放在 PSP_DEVINFO_DATA 中。
【参数说明】

  • DeviceInfoSet : 提供一个设备信息集合的句柄
  • MemberIndex : 指定一个要取得的设备信息成员序号,从0开始(如第几个麦克风)
  • DeviceInfoData : 指向SP_DEVINFO_DATA 结构的指针,关于指定成员的返回信息就放在该结构中
typedef struct _SP_DEVINFO_DATA {
  DWORD     cbSize; //cbSize设置成sizeof(PSP_DEVINFO_DATA )。
  GUID      ClassGuid;
  DWORD     DevInst;
  ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

【返回值】
成功返回True,否则返回False
如果要枚举全部设备信息成员,装载者首先应该将MemberIndex设为0调用SetupDiEnumDeviceInfo,然后递增MemberIndex(使用一个for循环),调用SetupDiEnumDeviceInfo,直至所有成员全部遍历(此时函数返回False,并且GetLastError返回ERROR_NO_MORE_ITEMS)。

【第三】SetupDiGetDeviceRegistryPropertyA

【函数原型】

BOOL SetupDiGetDeviceRegistryPropertyA(
  _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
);

【函数说明】
根据设备信息句柄和设备信息,查找指定设备信息,如设备地址、设备bus号、设备友好名称等
【参数说明】

  • DeviceInfoSet : 设备信息句柄。

  • DeviceInfoData : SP_DEVINFO_DATA结构体,包含DeviceInfoSet中的设备信息

  • Property取以下的值:

    • DeviceDesc:设备描述
    • SPDRP_HARDWAREID :硬件ID
    • SPDRP_MFG:供应商名字
    • SPDRP_LOCATION_INFORMATION:本地环境属性(如:PCI 总线 2、设备 10、功能 0)
    • SPDRP_FRIENDLYNAME:查询设备名称
    • SPDRP_ADDRESS : 查询设备的地址
    • SPDRP_BUSNUMBER : 查询设备的bus号
    • SPDRP_BUSTYPEGUID : 查询设备的GUID号
  • PropertyRegDataType:指向一个变量的指针,该变量接收正在检索的属性的数据类型。这是标准注册表数据类型之一。此参数是可选的,可以为 NULL。

  • PropertyBuffer:指向接收正在检索的属性的缓冲区的指针。如果此参数设置为 NULL,并且 PropertyBufferSize 也设置为零,则该函数将返回 RequiredSize 中缓冲区所需的大小

  • PropertyBufferSize:属性缓冲区的大小(以字节为单位)

  • RequiredSize:指向 DWORD 类型的变量的指针,该变量接收保存所请求属性的数据所需的属性缓冲区的大小(以字节为单位)。此参数是可选的,可以为 NULL
    【备注】
    这个函数主要原理是:从注册表中读取指定设备的属性。
    此函数还有一个增强版为SetupDiGetDevicePropertyW,可以获取设备所有属性。

【第四】SetupDiDestroyDeviceInfoList

【函数原型】

BOOL SetupDiDestroyDeviceInfoList( HDEVINFO DeviceInfoSet ); 

【函数说明】
销毁一个设备信息集合,并且释放所有关联的内存
【参数说明】
DeviceInfoSet : 要释放的设备信息句柄
【返回值】
成功返回非零,否则返回零

输出设备列表(以摄像头为例)

代码如下:

void show_camera_device() {

	//根据设备管理查找到摄像头 guid 即 {ca3e7ab9-b4c3-4ae6-8251-579ef933890f}
	//初始化 guid
	unsigned long  Data1 = 0xca3e7ab9;
	unsigned short Data2 = 0xb4c3;
	unsigned short Data3 = 0x4ae6;
	unsigned char  Data4[8] = {
		0x82,
		0x51,
		0x57,
		0x9e,
		0xf9,
		0x33,
		0x89,
		0x0f,
	};
	GUID camera_guid;
	camera_guid.Data1 = Data1;
	camera_guid.Data2 = Data2;
	camera_guid.Data3 = Data3;
	for(int i = 0;i < 8;i++)
		camera_guid.Data4[i] = Data4[i];

	//获得摄像头设备集合句柄 DeviceInfoSet
	HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW(&camera_guid, NULL, NULL, NULL);
	if (DeviceInfoSet == INVALID_HANDLE_VALUE)
		printf("error\n");
	//遍历摄像头集合中所有摄像头序列
	for (int i = 0; ; i++)
	{
		//存储第i个摄像头信息
		SP_DEVINFO_DATA DeviceInfoData;
		DeviceInfoData.cbSize = sizeof(DeviceInfoData);
		if (!SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DeviceInfoData))
			break;
		/*char szDeviceID[256] = {};
		DWORD dwTemp = 0;
		SetupDiGetDeviceInstanceIdW(DeviceInfoSet, &DeviceInfoData, (PWSTR)szDeviceID, 256, &dwTemp);*/

		DEVPROPKEY devicePropertyKey[256] = { 0 };
		DWORD RequiredSize = 0;
		DEVPROPTYPE PropertyType = 0;
		CHAR PropertyBuffer[8192] = { 0 }; //存储需要查询的信息
		DWORD DataT = 0;
		//获得当前摄像头的名字
		SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, &DeviceInfoData, SPDRP_FRIENDLYNAME,&DataT,reinterpret_cast<PBYTE>(PropertyBuffer), 8192, &RequiredSize);
		printf("name:%s\n", PropertyBuffer);
	}
	//销毁设备信息集合,并且释放相关内存
	SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}

image

参考

遍历Windows USB设备树的几种方法
Windows驱动之SetupDi系列函数

posted @ 2022-07-28 14:44  小超不挑食  阅读(702)  评论(0编辑  收藏  举报