最近在做一些关于注册表的程序,发现原来读取注册表都是大有讲究的,所以就想写一篇文章来记录下来。
一、操作系统
32位的Windows操作系统已经非常罕见了,现在主流的操作系统是64位的Windows。64位的系统为了兼容32位的应用程序,内置了一套模拟32位的子系统,它就是WOW64 (Windows-on-Windows 64-bit)。但是64位系统对于x64和Win32程序是分别对待的,注册表就是一个例子。
二、注册表视图
下面我们分别以x64方式(系统默认)和Win32的方式打开注册表编辑器,WOW64的路径是%systemroot%\syswow64。
分别运行regedit和%systemroot%\syswow64\regedit。
我们发现,x64和Win32打开的注册表视图显然是不同的。所以我们设计程序就需要考虑运行环境了。
三、C语言查询代码
注册表相关函数:RegOpenKeyEx,RegQueryInfoKey,RegCloseKey。
Win32程序查询注册表相关代码以及运行结果:
//如果SDK比较老, 就需要定义Windows版本
#ifndef _WIN32_WINNT_WIN7
#define _WIN32_WINNT_WIN7 0x0601
#endif
#ifndef WINVER
#define WINVER _WIN32_WINNT_WIN7
#endif
#include <stdio.h>
#include <stdlib.h>
//调用注册表API所需要的头文件
#include <windows.h>
#include <winbase.h>
int main()
{
HKEY hk;
LONG lReturn =RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer", 0, KEY_READ, &hk);
if(ERROR_SUCCESS ==lReturn) {
// 子键的数量, 最长子键的数据长度
DWORD dwSubKeys, dwMaxSubKeyLen;
// 当前子键所含的键值数量, 最长名称的数据长度, 最长数值的数据长度
DWORD dwVals, dwMaxValNameLen, dwMaxValLen;
RegQueryInfoKey(hk, NULL, NULL, NULL, &dwSubKeys, &dwMaxSubKeyLen, NULL, &dwVals, &dwMaxValNameLen, &dwMaxValLen, NULL, NULL);
printf("SubKeys =%u\r\nMaxSubKeyLen =%u\r\nVals =%u\r\nMaxValNameLen =%u\r\nMaxValLen =%u\r\n", (UINT)dwSubKeys, (UINT)dwMaxSubKeyLen,
(UINT)dwVals, (UINT)dwMaxValNameLen, (UINT)dwMaxValLen);
RegCloseKey(hk);
}
return 0;
}
显然,Win32程序所查询到的是32位注册表视图。那么,Win32程序有没有办法查询64位的注册表视图呢?答案是有的,办法是调用RegOpenKeyEx函数时在第四个参数中加入KEY_WOW64_64KEY标志就可以了。对于古董级别的SDK可能KEY_WOW64_64KEY都要自行定义,它的数值是0x0100。
代码修改部分以及运行结果:
LONG lReturn =RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer", 0, KEY_WOW64_64KEY |KEY_READ, &hk);
现在查询到的信息就与64位注册表视图相符了。
四、枚举注册表
相关函数:RegEnumValue,RegEnumKeyEx
这两个函数要特别说明,其中RegEnumValue第四个参数和第八个参数传递的指针既用作输入,也用作输出,函数返回后参数指向的数据也发生变化,所以调用函数前都需要赋值。RegEnumKeyEx的第四个参数也是如此。
代码以及运行结果:
//如果SDK比较老,就需要定义Windows版本
#define _WIN32_WINNT_WIN7 0x0601
#define WINVER _WIN32_WINNT_WIN7
#include <stdio.h>
#include <stdlib.h>
//调用注册表API所需要的头文件
#include <windows.h>
#include <winbase.h>
int main()
{
HKEY hk;
LONG lReturn =RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer", 0, KEY_WOW64_64KEY |KEY_READ, &hk);
if(ERROR_SUCCESS ==lReturn) {
// 子键的数量, 最长子键的数据长度
DWORD dwSubKeys, dwMaxSubKeyLen;
// 当前子键所含的键值数量, 最长名称的数据长度, 最长数值的数据长度
DWORD dwVals, dwMaxValNameLen, dwMaxValLen;
RegQueryInfoKey(hk, NULL, NULL, NULL, &dwSubKeys, &dwMaxSubKeyLen, NULL, &dwVals, &dwMaxValNameLen, &dwMaxValLen, NULL, NULL);
printf("SubKeys =%u\r\nMaxSubKeyLen =%u\r\nVals =%u\r\nMaxValNameLen =%u\r\nMaxValLen =%u\r\n", (UINT)dwSubKeys, (UINT)dwMaxSubKeyLen,
(UINT)dwVals, (UINT)dwMaxValNameLen, (UINT)dwMaxValLen);
//存放数据的空间定义得大一些
dwMaxSubKeyLen *=2;
dwMaxValNameLen *=2;
dwMaxValLen *=2;
PTCHAR strSubKey =(PTCHAR)calloc(dwMaxSubKeyLen, sizeof(TCHAR));
PTCHAR strName =(PTCHAR)calloc(dwMaxValNameLen, sizeof(TCHAR));
LPBYTE pbData =(LPBYTE)calloc(dwMaxValLen, sizeof(BYTE));
printf("打印数据列表:\r\n");
printf("|序号 |名称 |数据 |\r\n");
printf("|----------------------------------------------------------|\r\n");
for(DWORD i =0; i <dwVals; i++) {
DWORD dwNameLen =dwMaxValNameLen; //注意每次枚举数据都要初始化长度
DWORD dwDataLen =dwMaxValLen; //原因同上
DWORD dwType;
RegEnumValue(hk, i, strName, &dwNameLen, 0, &dwType, pbData, &dwDataLen);
for(int i =strlen(strName); i <17; i++) strcat(strName, " ");
for(int i =strlen((PTCHAR)pbData); i <31; i++) strcat((PTCHAR)pbData, " ");
printf("|%u |%s |%s |\r\n", i, strName, (PTCHAR)pbData);
printf("|----------------------------------------------------------|\r\n");
}
printf("打印节点列表: \r\n");
printf("|序号 |节点 |\r\n");
printf("|-------------------------|\r\n");
for(DWORD i =0; i <dwSubKeys; i++) {
DWORD dwSubKeyLen =dwMaxSubKeyLen; //同样的每次枚举都需要初始化成长度
RegEnumKeyEx(hk, i, strSubKey, &dwSubKeyLen, 0, 0, 0, 0);
for(int i =strlen(strSubKey); i <17; i++) strcat(strSubKey, " ");
printf("|%u |%s |\r\n", i, strSubKey);
printf("|-------------------------|\r\n");
}
free(strSubKey);
strSubKey =NULL;
free(strName);
strName =NULL;
free(pbData);
pbData =NULL;
RegCloseKey(hk);
}
printf("Press enter to quit ...");
getchar();
return 0;
}
对照前面的截图,这些输出结果也是符合相应的注册表视图的。