1. 环境
- Windows10 专业版 x64
- Qt5.15.2 MSVC2019 32bit
2. 目的
读取卸载列表,如下:
3. 方法
使用QSettings读取注册表项:
SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall
枚举所有子项的DisplayName:
4. 现象和原因
确实获取到了一部分列表,但是我想要找的却没有,可是我直接在regedit工具里面看是有的。经过一番搜索,很快就找到了原因:
Note: On Windows, for 32-bit programs running in WOW64 mode,
settings are stored in the following registry path:
HKEY_LOCAL_MACHINE\Software\WOW6432node.
大意就是Windows会将32位程序的注册表路径重定向,MSDN有更具体的解释,有兴趣可自行按关键字wow64查找。
我去翻找注册表的这个路径:
SOFTWARE\\WOW6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall
果然找到了匹配的数据,但是我想要的数据并不在这里,怎么才能读取正确的路径?
又是一番搜索,绝大部分的回答都是说要用Wow64DisableWow64FsRedirection来禁用系统重定向,但尝试之后没有效果。
5. 有效的解决办法
5.1 使用64位程序
按msdn的文档描述,64位程序是没有重定向问题的,可以直接读取对应的注册表项,那将编译工具集换成64位即可解决问题。但是我们的程序因为业务需求,是需要跑在一部分32位系统上的,所以这里有个变通的方案:
1. 主程序还是用32位
2. 读取注册表项的分别编译一个32位和64位的独立exe
3. 判断系统是32位的还是64位,然后调用对应的读取注册表程序,输出到文件
4. 主程序读取该文件
5.2 简单有效的方法
上面这个方法比较绕,后来侥幸搜到一篇博客,尝试之后有效,该方法不适用于QSettings,只能用win32 api来读取注册表。
这篇博客的主要思路是使用RegOpenKeyExA的系列api来读取注册项,然后通过KEY_WOW64_32KEY和KEY_WOW64_64KEY这两个值来控制读取位置,具体请参考:
https://www.xuebuyuan.com/1567776.html
最终的代码如下:
#include <windows.h>
#include <iostream>
using namespace std;
int main() {
HKEY key;
string rootKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
if (ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE, rootKey.c_str(), NULL, KEY_WOW64_64KEY | KEY_READ, &key)) {
return 1;
}
const int MAX_LEN = 256 * sizeof(char);
DWORD keyCount = MAX_LEN;
if (ERROR_SUCCESS != RegQueryInfoKey(key, NULL, NULL, NULL, &keyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) {
return 0;
}
char buf[MAX_LEN] = {0};
for (int i = 0; i < (int)keyCount; i++) {
DWORD keySize = MAX_LEN;
RegEnumKeyExA(key, i, buf, &keySize, NULL, NULL, NULL, NULL);
DWORD dwType;
HKEY subKey;
if (ERROR_SUCCESS == RegOpenKeyExA(key, buf, NULL, KEY_READ, &subKey)) {
char val[MAX_LEN] = {0};
keySize = MAX_LEN;
RegQueryValueExA(subKey, "DisplayName", 0, &dwType, (LPBYTE)val, &keySize);
cout << val << endl;
RegCloseKey(subKey);
}
}
RegCloseKey(key);
return 0;
}