读取注册表的方法

最近在做一些关于注册表的程序,发现原来读取注册表都是大有讲究的,所以就想写一篇文章来记录下来。

一、操作系统

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。

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;
}
加入KEY_WOW64_64KEY标志的运行结果
 

 

删除KEY_WOW64_64KEY标志的运行结果

 对照前面的截图,这些输出结果也是符合相应的注册表视图的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值