注册表是唯一靠谱的已安装软件获取途径,因win32_product会引发卡顿且仅覆盖msi安装软件;必须双路径读取hkey_local_machinesoftwaremicrosoftwindowscurrentversionuninstall(64位)和wow6432node下对应路径(32位),并显式指定key_wow64_64key或key_wow64_32key。

为什么直接读注册表是唯一靠谱的途径
Windows 不提供标准 API 列出“已安装软件”,Win32_Product WMI 类看似可用,但实际会触发 MSI 数据库全盘扫描,导致系统卡顿、CPU 飙升,且仅返回通过 Windows Installer 安装的软件(大量绿色软件、EXE 直接安装的程序完全漏掉)。真正稳定、快速、覆盖广的方式只有读取注册表。
关键路径有两个:
-
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionUninstall(64位软件,或32位系统) -
HKEY_LOCAL_MACHINESOFTWAREWOW6432NodeMicrosoftWindowsCurrentVersionUninstall(64位系统下的32位软件)
注意:必须用 RegOpenKeyEx + KEY_WOW64_32KEY / KEY_WOW64_64KEY 显式指定视图,否则在 64 位进程里默认只能看到 64 位键(WOW6432Node 不会自动映射)。
如何用 C++ 安全遍历 Uninstall 注册表项
注册表下每个子键对应一个软件,但不是所有子键都有有效信息(比如空键、系统保留键),必须逐个读取 DisplayName 值来过滤。不能只靠键名判断。
实操要点:
- 用
RegEnumKeyEx枚举所有子键名,每次调用前先RegOpenKeyEx打开父键,结束后RegCloseKey - 对每个子键,再用
RegOpenKeyEx打开它,然后调用RegQueryValueEx读DisplayName(REG_SZ类型) - 若
RegQueryValueEx返回ERROR_FILE_NOT_FOUND或读到空字符串,跳过该键 - 同时建议读
DisplayVersion和Publisher,它们存在概率高,且无害
示例片段(简化):
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) {
WCHAR szSubKeyName[256];
DWORD dwSize;
for (DWORD i = 0; ; i++) {
dwSize = _countof(szSubKeyName);
if (RegEnumKeyEx(hKey, i, szSubKeyName, &dwSize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
// ... 打开子键并读 DisplayName
}
RegCloseKey(hKey);
}
32/64 位兼容性最容易踩的坑 很多代码只查一个路径,结果在 64 位 Windows 上漏掉一半软件(尤其是 Chrome、微信这类 32 位主流软件)。这不是“可选”,而是必须双路径处理。
关键点:
- 即使你的程序是 64 位,也必须显式访问
WOW6432Node路径(不能依赖重定向) - 不要用
KEY_WOW64_32KEY打开HKEY_LOCAL_MACHINESOFTWAREMicrosoft...—— 这只会让你看到 32 位视图下的 64 位路径(基本为空) - 正确做法:分别用
KEY_WOW64_64KEY访问原路径,用KEY_WOW64_32KEY访问WOW6432Node路径 - 如果程序本身是 32 位,则无需指定 flag,系统自动走 32 位视图;但为统一逻辑,仍建议显式指定
获取到的数据为什么看起来“不全”
注册表方式本身就有天然局限:便携软件、MSIX 应用、Store 应用、手动解压即用的工具(如 Notepad++ 绿色版)、甚至部分 MSI 安装包(禁用了卸载注册)都不会写入 Uninstall 键。
能拿到的,基本就是“控制面板 → 程序和功能”里显示的那些 —— 这不是 bug,是设计使然。如果你需要更广覆盖,得额外结合:
-
Get-AppxPackagePowerShell 命令(UWP/Store 应用) - 扫描常见安装目录(
C:Program Files、C:Program Files (x86))下的.exe文件(不可靠,易误报) - 解析
HKLMSOFTWAREClients等特定类别键(如邮件客户端、浏览器)
但这些都属于补充手段,无法替代注册表作为主数据源的地位。
注册表键名无规律、值内容格式不一、部分软件写错DisplayName(比如留空或填乱码),这些都不是你能改的——能做的,只是健壮地跳过异常,别让整个枚举崩掉。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











