用setupapi获取驱动列表必须先调用setupdigetclassdevs枚举设备实例,再逐个提取驱动信息;不可依赖注册表或drivers目录,需正确释放句柄、处理多驱动栈及权限限制。

用 SetupAPI 获取驱动列表必须先枚举设备实例
直接调用 SetupDiGetClassDevs 是唯一可靠方式,不能靠遍历注册表或读取 drivers 目录——那些路径不等于“已加载驱动”,很多只是待安装的 INF 文件。你需要先获取设备实例句柄集合,再逐个提取驱动信息。
-
SetupDiGetClassDevs传入GUID_NULL和NULL可枚举所有设备类(含非即插即用设备),但性能较差;更推荐按常见类 GUID 分批查,比如GUID_DEVCLASS_NET、GUID_DEVCLASS_DISPLAY - 必须指定
DIGCF_ALLCLASSES | DIGCF_PRESENT标志,否则漏掉未连接硬件的驱动(如蓝牙适配器未开机时的驱动) - 返回的
HDEVINFO句柄必须在最后用SetupDiDestroyDeviceInfoList释放,否则泄漏句柄
从设备实例读取驱动服务名和描述要调用两次 SetupDiGetDeviceRegistryProperty
一个设备实例可能对应多个驱动(如过滤驱动叠加),但 SetupDiGetDeviceRegistryProperty 默认只返回主驱动。要拿到完整驱动栈,得先查 SPDRP_SERVICE 得到服务名,再用该服务名打开注册表键 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{service_name} 读 DisplayName 和 ImagePath。
-
SPDRP_DRIVERLETTER和SPDRP_CLASSGUID这类属性多数时候为空,别依赖它们判断驱动有效性 - 有些驱动(如
WudfRd)注册表项下没有DisplayName,需 fallback 到读取DriverPackageId或直接解析ImagePath文件名 - 调用
SetupDiGetDeviceRegistryProperty前必须确保缓冲区足够大,建议先用NULL参数调一次获取所需长度,再分配内存重试
Win32_PnPSignedDriver WMI 查询快但信息不全
用 WbemScripting.SWbemLocator 查询 Win32_PnPSignedDriver 类能绕过 SetupAPI 复杂流程,10 行代码就能列出大部分驱动,但实际跑起来会发现:签名状态字段常为空、驱动文件版本缺失、无法区分同一设备下的上下层驱动(如 usbccgp + usbhub)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 查询语句用
SELECT Name, DeviceID, DriverVersion FROM Win32_PnPSignedDriver最稳妥,加WHERE IsSigned = TRUE反而可能漏掉微软内置无显式签名的驱动 - WMI 返回的
DeviceID是 PnP ID(如PCIVEN_10DE&DEV_248C&SUBSYS_8675103C&REV_A1&3A9B2D3F&0&0008),和 SetupAPI 的DevInst不互通,不能混用 - 首次查询耗时明显(WMI 服务需加载驱动元数据),后续调用才快;若进程短命(如命令行工具),不如直接上 SetupAPI
权限不足时 SetupDiEnumDeviceInfo 会静默失败
普通用户进程调用 SetupDiEnumDeviceInfo 遇到某些系统级设备(如 ACPI、PCI root bus)会返回 FALSE 且 GetLastError() 为 ERROR_ACCESS_DENIED,但不会崩溃——这容易被当成“没设备”误判。必须检查每一步的错误码,不能只看返回值真假。
- 提升权限不是万能解法:即使以管理员运行,某些内核驱动(如
hvbootflt)仍拒绝暴露信息,这是设计使然 - 遇到
ERROR_NO_MORE_ITEMS才表示枚举结束,其他错误(包括ERROR_INVALID_PARAMETER)都应记录并跳过当前设备,继续下一个 - 不要用
try/catch捕获 SetupAPI 错误——它纯 C API,错误全靠GetLastError(),C++ 异常机制对它无效
驱动信息天然分散在设备管理器、注册表、WMI、内核对象多个层面,没有单点入口。最稳的路径是 SetupAPI 主干 + 注册表辅助补全,但得接受部分驱动(尤其是 Miniport、Filter 类)永远拿不到完整路径或版本号。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










