项目背景
我需要通过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可以直接复制使用。如果有人能解答我的问题,那就更好了!感谢!