C++设备管理器


项目背景

我需要通过C++查询设备管理器中的某个设备是否存在,然后找到该设备的父节点和兄弟节点和子节点。所以我的code就是用来实现上面的内容。


一、代码

直接上代码

// DeviceManager.hpp
#include <iostream>
#include <Windows.h>
#include <cfgmgr32.h>
#include <setupapi.h>   
#include <vector>
#pragma comment(lib, "setupapi.lib")

class DeviceManager
{
public:
	/*
	* @brief	查询可以查到的所有设备信息
	* @param	parentInst - 当前节点
	*
	* @author 	Canliang Wu
	* @day		2024/01/02
	*/
	static bool GetAllDevices()
	{
		HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, (DIGCF_ALLCLASSES | DIGCF_PRESENT));
		if (INVALID_HANDLE_VALUE == hDevInfo)
			return false;

		SP_DEVINFO_DATA sDevInfoData;
		memset(&sDevInfoData, 0x00, sizeof(SP_DEVICE_INTERFACE_DATA));
		sDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

		// 遍历设备树
		for (int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &sDevInfoData); i++)
		{
			TCHAR szDis[MAX_PATH * 4] = { 0x00 };// 存储设备实例ID
			DWORD nSize = 0;
			if (!SetupDiGetDeviceInstanceIdW(hDevInfo, &sDevInfoData, szDis, sizeof(szDis) / sizeof(szDis[0]), &nSize))
			{
				// 无效设备
				if (INVALID_HANDLE_VALUE != hDevInfo)
				{
					SetupDiDestroyDeviceInfoList(hDevInfo);
					hDevInfo = INVALID_HANDLE_VALUE;
				}

				return false;
			}

			// 获取友好名称
			TCHAR szFN[MAX_PATH * 4] = { 0x00 };
			SetupDiGetDeviceRegistryProperty(hDevInfo, &sDevInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)szFN, sizeof(szFN), NULL);
			std::wstring friendName(szFN);

			// 获取硬件ID(包含VID和PID的字符串)
			TCHAR szHID[MAX_PATH * 4] = { 0x00 }; // 存储设备硬件ID
			SetupDiGetDeviceRegistryProperty(hDevInfo, &sDevInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)szHID, sizeof(szHID), NULL);
			std::wstring hardwareID(szHID);

			std::wcout << L"Friendly name: " << friendName << ", HID: " << hardwareID << std::endl;
		}

		if (hDevInfo != INVALID_HANDLE_VALUE)
		{
			SetupDiDestroyDeviceInfoList(hDevInfo);
			hDevInfo = INVALID_HANDLE_VALUE;
		}

		return true;
	}

	/*
	* @brief	查询当前节点的子节点、当前节点的子节点的子节点、当前节点的子节点的兄弟节点的设备信息
	* @param	parentInst - 当前节点
	*
	* @author 	Canliang Wu
	* @day		2024/01/02
	*/
	static bool QueryChildNode(const DEVINST& parentInst)
	{
		DEVINST childDevInst = NULL;

		// 获取第一个子节点
		if (CM_Get_Child(&childDevInst, parentInst, 0) != CR_SUCCESS) return false;

		// 遍历一层子节点
		while (childDevInst)
		{
			// 获取友好名称
			TCHAR str1[1024] = { '0' };
			ULONG len1 = sizeof(TCHAR) * 1024;
			auto errorCode = CM_Get_DevNode_Registry_Property(childDevInst, CM_DRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(str1), &len1, 0);
			if (errorCode == CR_SUCCESS)
			{
				std::wstring friendName(str1);

				std::wcout << "Friendly name: " << friendName << std::endl;
			}

			// 获取设备描述
			TCHAR str2[1024] = { '0' };					// 注意,这里不能直接使用str1,否则会一旦友好名称查询失败,这里就会返回error=26
			ULONG len2 = sizeof(TCHAR) * 1024;
			errorCode = CM_Get_DevNode_Registry_Property(childDevInst, CM_DRP_DEVICEDESC, NULL, reinterpret_cast<PBYTE>(str2), &len2, 0);
			if (errorCode == CR_SUCCESS)
			{
				std::wstring deviceDesc(str2);

				std::wcout << "Device describe: " << deviceDesc << std::endl;
			}

			// 递归遍历设备的子节点
			QueryChildNode(childDevInst);

			// 获取下一个兄弟节点
			if (CM_Get_Sibling(&childDevInst, childDevInst, 0) != CR_SUCCESS)
			{
				break;
			}
		}

		return true;
	}
	
	/*
	* @brief	查询当前节点的父节点信息
	* @param	childData - 当前节点
	*
	* @author 	Canliang Wu
	* @day		2024/01/02
	*/
	static bool QueryParentNode(SP_DEVINFO_DATA childData)
	{
		DEVINST parentInst = NULL;
		if (CM_Get_Parent(&parentInst, childData.DevInst, 0) != CR_SUCCESS)
		{
			return false;
		}

		// 获取友好名称
		TCHAR str1[1024] = { '0' };
		ULONG len1 = sizeof(TCHAR) * 1024;
		auto errorCode = CM_Get_DevNode_Registry_Property(parentInst, CM_DRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(str1), &len1, 0);
		if (errorCode == CR_SUCCESS)
		{
			std::wstring friendName(str1);

			std::wcout << "Friendly name: " << friendName << std::endl;
		}

		return true;
	}
};

二、遇到的问题

我遇到的问题在于这段代码:

// 获取友好名称
TCHAR str1[1024] = { '0' };
ULONG len1 = sizeof(TCHAR) * 1024;
auto errorCode = CM_Get_DevNode_Registry_Property(childDevInst, CM_DRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(str1), &len1, 0);
if (errorCode == CR_SUCCESS)
{
	std::wstring friendName(str1);

	std::wcout << "Friendly name: " << friendName << std::endl;
}

// 获取设备描述
TCHAR str2[1024] = { '0' };					// 注意,这里不能直接使用str1,否则会一旦友好名称查询失败,这里就会返回error=26
ULONG len2 = sizeof(TCHAR) * 1024;
errorCode = CM_Get_DevNode_Registry_Property(childDevInst, CM_DRP_DEVICEDESC, NULL, reinterpret_cast<PBYTE>(str2), &len2, 0);
if (errorCode == CR_SUCCESS)
{
	std::wstring deviceDesc(str2);

	std::wcout << "Device describe: " << deviceDesc << std::endl;
}

假设两次调用CM_Get_DevNode_Registry_Property()都使用str1进行填充。
那么,如果我第一次调用CM_Get_DevNode_Registry_Property()查询友好名称失败(我的返回是 errorCode = CR_NO_SUCH_DEVICE_INTERFACE),那么第二次调用CM_Get_DevNode_Registry_Property()查询设备描述则一定失败(返回 errorCode = CR_WRONG_TYPE)。
我们知道,对于设备管理器的设备,并不是每一个设备都有友好名称和设备描述(可以通过设备管理器查看)。所以我猜测第一个返回的原因就是因为它没有友好名称。但是仍然不知道第二个错误是为什么产生的。但是改成str2就没问题了。

在这里插入图片描述


总结

上面的class可以直接复制使用。如果有人能解答我的问题,那就更好了!感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值