Windows 注册表相关API总结

一、注册表简介

注册表实际上是一个管理配置系统运行参数的核心数据库,它记录了安装软件与运行程序的关联关系,计算机的硬件配置等信息。可以说计算机上所有针对硬件、软件、网络的操作都是源于注册表的。
可以使用 regedit.exe 这个系统提供的注册表编辑器去管理编辑注册表,他只是一个编辑器不是注册表的文件。
在这里插入图片描述

如上图所示,注册表预设有五个根键:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USER
HKEY_CURRENT_CONFIG

根键展开后可以看到跟键的子健(子项):像 "System, Software等都是HKEY_CURRENT_CONFIG的子健(子项)。
就像文件夹一样,每个键都可以创建子项,同时也可以拥有键值项。
键值项由3部分组成:名称、类型、值。

几个根键的用途说明:
  • HKEY_LOCAL_MACHINE 根键中包含了操作系统、安装软件及硬件的相关信息。如计算机总线类型、系统可用内存、当前装载了哪些设备驱动程序以及启动控制数据等。
    实际上,HKEY_LOCAL_MACHINE 根键保存着注册表中的大部分信息,而另外4个根键都是其子键的别名。

  • HKEY_CURRENT_USER 根键包含这当前登录到计算机上的用户的配置文件。其子键包含着环境变量、个人程序组、桌面设置、网络连接、打印机和应用程序首选项等信息。
    计算机把当前用户的信息映射到这个根键下,若未激活用户配置,则它指向子键 HKEY_USERS.DEFAULT。

  • HKEY_CLASSES_ROOT 根键记录的是系统中各类文件与其应用程序之间的对应关系,即记录了某类文件和打开该类文件的应用程序之间的相互关联关系。
    HKEY_CLASSES_ROOT 根键是 HKEY_LOCAL_MACHINE\SOFTWARE\Classes 的快捷方式,是注册表的一个最大分支,包括了成千上万的与程序、文件相关联的键和值以及ActiveX类的定义等内容。

  • HKEY_USERS 根键下包含了计算机的所有用户的信息。用户根据个人爱好设置的诸如桌面、背景、开始菜单程序项、应用程序快捷键、显示字体、屏幕节电设置等信息均记录在这个跟建中
    HKEY_CURRENT_USER 也是 HKEY_USERS 其中的的一个快捷键部分。

  • HKEY_CURRENT_CONFIG 根键包含的主要内容是计算机的当前配置情况,如显示器、打印机等可选外部设备及其设置信息等。

二、常用API介绍

1.RegCreateKeyEx() 创建注册表键

MSDN: RegCreateKeyExA function (winreg.h)
功能:创建或打开注册表键。
函数原型:

LONG RegCreateKeyEx(
              HKEY hKey,        	// 已打开的键的句柄 (RegOpenKeyEx, RegCreateKeyEx 的返回值) 或者 预定义的值( 即根键)。
              LPCTSTR lpSubKey,   	// 指向 要创建或要打开的子健名称。
              DWORD Reserved,     	// 保留值必须为 0,
              LPTSTR lpClass,     	// 字符串指针,指向用户自定义的键类别名称。可以设为NULL。
              DWORD dwOptions,  	//  新创建的键的属性。
              REGSAM samDesired,   // 键的访问权限。
              LPSECURITY_ATTRIBUTES lpSecurityAttributes,   // 指向 SECURITY_ATTRIBUTES 结构的指针,用于定义返回的句柄是否可以被子进程继承,为 NULL 表示不继承。
              PHKEY phkResult,     // 指向新创建或打开的键的句柄的指针,保存返回的句柄。
              LPDWORD lpdwDisposition  //  指明键是被创建还是被打开的
              ); 

参数:
【入参】hKey: 已经打开的注册表键的句柄。

可以是以下的值:

  • HKEY_CLASSES_ROOT
  • HKEY_CURRENT_CONFIG
  • HKEY_CURRENT_USER
  • HKEY_LOCAL_MACHINE
  • HKEY_USERS
  • RegOpenKeyEx或RegCreateKeyEx 返回的phkResult

【入参】dwOptions: 键的属性。

可以是以下的值:

  • REG_OPTION_NON_VOLATILE 新创建的键为一个非短暂性的键 (数据信息保存在文件中,当系统重新启动时,数据信息恢复)
  • REG_OPTION_VOLATILE 新创建的键为一个短暂性的键(数据信息保存在内存中)。
  • REG_OPTION_BACKUP_RESTORE 仅在WINNT中支持,可以提供优先级支持。

【入参】samDesired: 键的访问权限。

  • KEY_ALL_ACCESS 包含所有权限。
  • KEY_CREATE_LINK 系统保留。
  • KEY_CREATE_SUB_KEY 允许创建子键。
  • KEY_ENUMERATE_SUB_KEYS 允许枚举子健。
  • KEY_EXECUTE 等同于KEY_READ。
  • KEY_NOTIFY 允许提供更改通知(详见 RegNotifyChangeKeyValue)
  • KEY_QUERY_VALUE 允许查询键值
  • KEY_READ 读取权限,包括STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS 和 KEY_NOTIFY 。
  • KEY_SET_VALUE 创建、删除、设置键值。
  • KEY_WOW64_32KEY 32位注册表/64位注册表路径重定向,设置后将访问32位注册表路径。
  • KEY_WOW64_64KEY 32位注册表/64位注册表路径重定向,设置后将访问64位注册表路径。
  • KEY_WRITE 写权限包括 STANDARD_RIGHTS_WRITE, KEY_SET_VALUE 和

【出参】phkResult: 创建或打开的键的句柄。

【出参】lpdwDisposition: 指明键是被创建还是被打开的。
REG_CREATED_NEW_KEY 键先前不存在,现在被创建。
  REG_OPENED_EXISTING_KEY 键先前已存在,现在被打开。

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。

关于KEY_WOW64_32KEY/KEY_WOW64_64KEY几点说明
  1. 只适用于64位系统,以下所说情况都是在64位系统下。
  2. 在64位系统中,64位程序默认访问64位注册表,32位程序默认访问32位注册表,两者路径是不一样的。
    比如 :分别用64位程序和32位程序访问注册表路径 “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft”
    64位程序访问的真实路径就是“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft”。
    而32位程序访问的真实路径是"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft"。
  3. 如果想用32位程序访问“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft” ,需要在samDesired 添加KEY_WOW64_64KEY。同理64位程序如果想访问Wow6432Node目录,需要使用KEY_WOW64_32KEY。
  4. 示例
    //32位程序访问64位注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
    DWORD lRtn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft", 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hKey);
    //64位程序访问32位注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft
    DWORD lRtn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft", 0, KEY_ALL_ACCESS|KEY_WOW64_32KEY, &hKey);


2.RegOpenKeyEx() 打开注册表

MSDN:RegOpenKeyExA function (winreg.h)
功能:打开注册表键。
函数原型:

LSTATUS RegOpenKeyExA(
  HKEY   hKey,		//已打开的键的句柄或根键
  LPCSTR lpSubKey,	//子健相对路径
  DWORD  ulOptions, //一般设为0 ,也可以是REG_OPTION_OPEN_LINK表示该键为符号链接(未使用过,待测试)
  REGSAM samDesired,//访问需要的权限
  PHKEY  phkResult  //返回的键句柄
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。

3.RegDeleteKeyEx() 删除注册表键

MSDN: RegDeleteKeyExA function (winreg.h)
功能:删除注册表键。
函数原型:

LSTATUS RegDeleteKeyExA(
  HKEY   hKey,			//已打开的键的句柄或根键
  LPCSTR lpSubKey,		//子健相对路径
  REGSAM samDesired,	//访问32位路径还是64位注册表路径  使用KEY_WOW64_32KEY 或 KEY_WOW64_64KEY
  DWORD  Reserved		//保留,必须为0
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。

4.RegCloseKey() 关闭注册表句柄

MSDN:RegCloseKey function (winreg.h)
功能:关闭已经打开的注册表句柄。
函数原型:

LSTATUS RegCloseKey(
  HKEY hKey				//已打开的键的句柄
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。

5.RegSetValueEx() 写注册表

MSDN:RegSetValueExA function (winreg.h)
功能:设置注册表的键值项。
函数原型:

LSTATUS RegSetValueExA(
  HKEY       hKey,				//已打开的键的句柄
  LPCSTR     lpValueName,		//键值名称,如果为NULL或“”,则设置键值名为“默认”的项
  DWORD      Reserved,			//保留,必须为0
  DWORD      dwType,			//设置的键值数据类型
  const BYTE *lpData,			//指向键值数据的指针
  DWORD      cbData				//设置的键值数据长度
);

【入参】dwType:设置的键值数据类型
可以是以下值:

  • REG_BINARY 二进制数据
  • REG_DWORD 32字节数据
  • REG_DWORD_LITTLE_ENDIAN 小端的4字节数据(windows是基于小端处理器设计的,所以等同于REG_DWORD)
  • REG_DWORD_BIG_ENDIAN 大端的4字节数据
  • REG_EXPAND_SZ 可扩展的字符串,此类型的键值中存在的%xxx%的部分会被系统解释,而REG_SZ不会
  • REG_LINK 指向符号链接的注册表项路径的字符串
  • REG_MULTI_SZ 多个字符串,用\0分隔,例如:String1\0String2\0String3\0LastString\0\0
  • REG_NONE 未定义的类型
  • REG_QWORD 8字节数据
  • REG_QWORD_LITTLE_ENDIAN 等同于REG_QWORD
  • REG_SZ 字符串

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。


6.RegQueryValueEx() 读注册表

MSDN: RegQueryValueExA function (winreg.h)
功能:根据名称获取对应注册表项的数据类型和数据。
(要确保返回的任何字符串值(REG_SZ、REG_MULTI_SZ和REG_EXPAND_SZ)都以null结尾,请使用RegGetValue函数。)
函数原型:

LSTATUS RegQueryValueExA(
  HKEY    hKey,					//已打开的键的句柄
  LPCSTR  lpValueName,			//键值名称,如果为NULL或“”,则设置键值名为“默认”的项
  LPDWORD lpReserved,			//保留,必须为0
  LPDWORD lpType,				//【出参】,返回数据类型
  LPBYTE  lpData,				//【出参】, 返回数据
  LPDWORD lpcbData				//【出参】, 返回数据长度
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS。否则返回非零的错误代码。


7.RegGetValue() 读注册表

MSDN:RegGetValueA function (winreg.h)
功能:根据名称获取对应注册表项的数据类型和数据。
函数原型:

LSTATUS RegGetValueA(
  HKEY    hkey,				//已打开的键的句柄,一般是根键
  LPCSTR  lpSubKey,			//hKey的子键路径
  LPCSTR  lpValue,			//键值项名称
  DWORD   dwFlags,			//对于返回键值类型的限制,如果不满足,函数会执行失败
  LPDWORD pdwType,			//【出参】 返回的数据类型
  PVOID   pvData,			//【出参】, 返回数据
  LPDWORD pcbData			//【出参】, 返回数据长度
);

【入参】 dwFlags:对于返回键值类型的限制,如果不满足,函数会执行失败。
可以是以下值或它们的组合(按位或|):

  • RRF_RT_ANY 无任何限制
  • RRF_RT_DWORD 允许32位RRF_RT_REG_BINARY或RRF_RT_REG_DWORD类型
  • RRF_RT_QWORD 允许64位RRF_RT_REG_BINARY或RRF_RT_REG_QWORD类型
  • RRF_RT_REG_BINARY 仅允许REG_BINARY类型
  • RRF_RT_REG_DWORD 仅允许REG_DWORD类型
  • RRF_RT_REG_EXPAND_SZ 仅允许 REG_EXPAND_SZ类型
  • RRF_RT_REG_MULTI_SZ 仅允许 REG_MULTI_SZ类型
  • RRF_RT_REG_NONE 仅允许 REG_NONE
  • RRF_RT_REG_QWORD 仅允许 REG_QWORD
  • RRF_RT_REG_SZ仅允许 REG_SZ
  • RRF_NOEXPAND 当数据类型为REG_EXPAND_SZ时,不自动展开环境变量字符串。
  • RRF_ZEROONFAILURE 当pvData 不为NULL时,执行失败会把缓冲区全置为0。
  • RRF_SUBKEY_WOW6464KEY 访问64位注册表路径。
  • RRF_SUBKEY_WOW6432KEY 访问32位注册表路径。
RegGetValue()较于RegQueryValueEx()优点:

1.RegGetValue不需要打开注册表句柄(这个API自动会打开和关闭句柄)

2.RegGetValue可以限制键值的类型,如果注册表中的类型跟自己想要的类型(由dwFlags设置的)不符,函数会返回0x0000065E错误 :“这个类型的数据不受支持。 ” 。值得注意的是,即使此时返回值不是ERROR_SUCCESS ,pdwType 和pvData仍然会返回正确的数据。

3.RegQueryValueEx不保证查询的字符串已NULL结尾,而RegGetValue会进行检查。(经过个人测试,并未发现此类情况,RegQueryValueEx仍然需要包含\0结尾的大小的buffer才能执行成功。只不过当数据类型是REG_MULTI_SZ 时,RegQueryValueEx返回的数据结尾是\0,而RegGetValue返回的数据结尾是\0\0,环境: win7 64)。


8.RegEnumKeyEx() 枚举注册表子健

MSDN:RegEnumKeyExA function (winreg.h)
功能:枚举子健名称。
函数原型:

LSTATUS RegEnumKeyExA(
  HKEY      hKey,			//已打开的键的句柄
  DWORD     dwIndex,		//子健索引
  LPSTR     lpName,			//【出参】子健名称
  LPDWORD   lpcchName,		//【入参/出参】子健名称缓冲区大小/返回的子健名称长度
  LPDWORD   lpReserved,		//保留,必须为0
  LPSTR     lpClass,		//【出参】类名名称,如果不需要,可以传NULL
  LPDWORD   lpcchClass,		//【入参/出参】类名缓冲区大小/返回的类名长度
  PFILETIME lpftLastWriteTime	// FILETIME指针,返回子健最后的更改日期,可以创NULL
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS,如果全部枚举完毕,返回ERROR_NO_MORE_ITEMS,其他情况返回非零的错误代码。

9.RegEnumValue() 枚举键值项

MSDN:RegEnumValueA function (winreg.h)
功能:枚举键值项。
函数原型:

LSTATUS RegEnumValueA(
  HKEY    hKey,				//已打开的键的句柄
  DWORD   dwIndex,			//键值项索引
  LPSTR   lpValueName,		//【出参】键值项名称
  LPDWORD lpcchValueName,	//【入参/出参】键值项名称缓冲区大小/返回的键值项名称长度
  LPDWORD lpReserved,		//保留,必须为0
  LPDWORD lpType,			//【出参】键值项的数据类型
  LPBYTE  lpData,			//【出参】键值项数据
  LPDWORD lpcbData			//【入参/出参】数据长度
);

【返回值】如果函数调用成功,则返回 ERROR_SUCCESS,如果全部枚举完毕,返回ERROR_NO_MORE_ITEMS,其他情况返回非零的错误代码。

示例代码

#include <iostream>
#include <windows.h>
using namespace std;
int main() {
    HKEY hKey = NULL;
    LONG lRtn = 0;
    DWORD dwDisposition = 0;
    
    //创建注册表键
    lRtn = RegCreateKeyEx(  HKEY_CURRENT_CONFIG, 
                            "Software\\nibin", 
                            0, 
                            NULL, 
                            REG_OPTION_NON_VOLATILE, 
                            KEY_ALL_ACCESS, 
                            NULL, 
                            &hKey,
                            &dwDisposition );
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegCreateKeyEx error   :  0x" << hex << lRtn << endl;
        return -1;
    }
    if (dwDisposition == REG_CREATED_NEW_KEY) {
        cout << "创建新键 HKEY_CURRENT_CONFIG\\Software\\nibin" << endl;
    }
    else {
        cout << "打开已存在的键 HKEY_CURRENT_CONFIG\\Software\\nibin" << endl;
    }
    RegCloseKey(hKey);  //关闭注册表句柄
    hKey = NULL;

    //打开注册表,权限设为KEY_ALL_ACCESS,以便下一步读写操作
    lRtn = RegOpenKeyEx(HKEY_CURRENT_CONFIG, "Software\\nibin", 0, KEY_ALL_ACCESS, &hKey);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegOpenKeyEx error   :  0x" << hex << lRtn << endl;
        return -1;
    }

    //写注册表
    char writeData[] = { "Hello Registry!" };
    DWORD cbWriteData = sizeof(writeData);
    lRtn = RegSetValueEx(hKey, "RegeditTest", 0, REG_SZ, (BYTE*)writeData, cbWriteData);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegSetValueEx error   :  0x" << hex << lRtn << endl;
        RegCloseKey(hKey);  //关闭注册表句柄
        hKey = NULL;
        return -1;
    }

    DWORD dwType;
    DWORD dataLen = 0;
    //读注册表,首先传NULL获取缓冲区需要的大小,如果已知数据的大小,可以直接传入一个足够大数组。
    lRtn = RegQueryValueEx(hKey, "RegeditTest", 0, &dwType, NULL, &dataLen);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegQueryValueEx error   :  0x" << hex << lRtn << endl;
        RegCloseKey(hKey);  //关闭注册表句柄
        hKey = NULL;
        return -1;
    }
    BYTE* readData = new BYTE[dataLen];
    //读注册表
    lRtn = RegQueryValueEx(hKey, "RegeditTest", 0, &dwType, readData, &dataLen);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegQueryValueEx error  :  0x" << hex << lRtn << endl;
        RegCloseKey(hKey);  //关闭注册表句柄
        hKey = NULL;
        return -1;
    }
    else {
        cout << "use RegQueryValueEx readData : " << (char*)readData << endl;
    }
    delete[] readData;
    readData = NULL;
    RegCloseKey(hKey);  //关闭注册表句柄
    hKey = NULL;

    char getData[64] = { 0 };
    dataLen = sizeof(getData);
    //使用RegGetValue读注册表不需要open和close操作
    lRtn = RegGetValue(HKEY_CURRENT_CONFIG, "Software\\nibin", "RegeditTest", RRF_RT_ANY, &dwType, getData, &dataLen);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegGetValue error  :  0x" << hex << lRtn << endl;
        RegCloseKey(hKey);  //关闭注册表句柄
        hKey = NULL;
        return -1;
    }
    else {
        cout << "use RegGetValue readData : " << getData << endl;
    }


    //打开注册表,权限设为KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,枚举子健,读键值项数据
    lRtn = RegOpenKeyEx(HKEY_CURRENT_CONFIG, "Software", 0, KEY_ENUMERATE_SUB_KEYS| KEY_QUERY_VALUE, &hKey);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegOpenKeyEx error  :  0x" << hex << lRtn << endl;
        return -1;
    }

    //在枚举子健和键值项之前最好先调用RegQueryInfoKey 获取子健和键值项的数目,用来结束枚举循环;
    //也可以不调用RegQueryInfoKey,直接判断RegEnumKeyEx和RegEnumValue返回值来结束枚举循环。
    DWORD cSubKeys = 0;
    DWORD cValues = 0;
    lRtn = RegQueryInfoKey(hKey, NULL, NULL, 0, &cSubKeys, NULL, NULL, &cValues, NULL, NULL, NULL, NULL);
    if (lRtn != ERROR_SUCCESS) {
        cout << "RegQueryInfoKey error  :  0x" << hex << lRtn << endl;
        RegCloseKey(hKey);  //关闭注册表句柄
        hKey = NULL;
        return -1;
    }
    else {
        cout << "RegQueryInfoKey  HKEY_CURRENT_CONFIG\\Software has " << cSubKeys 
        << " SubKeys and " << cValues << " Items" << endl;
    }

    lRtn = ERROR_SUCCESS;
    char szSubKeyName[1024] = { 0 };
    DWORD cbSubKeyName = sizeof(szSubKeyName);
    //枚举HKEY_CURRENT_CONFIG\Software子健
    for (int dwIndex = 0; dwIndex < cSubKeys; ++dwIndex) {
        lRtn = RegEnumKeyEx(hKey, dwIndex, szSubKeyName, &cbSubKeyName, 0, 0, 0, 0);
        if (lRtn == ERROR_SUCCESS) {
            cout << "EnumSubKey : " << szSubKeyName << endl;
            cbSubKeyName = sizeof(szSubKeyName);//如果是用同一数组保存Name,注意重置cbSubKeyName为szSubKeyName分配的空间大小
        }
        else {
            cout << "RegEnumKeyEx error :  0x" << hex << lRtn << endl;
        }
    }

    lRtn = ERROR_SUCCESS;
    char szItemName[1024] = { 0 };
    DWORD cbItemName = sizeof(szItemName);
    BYTE Data[1024] = { 0 };
    DWORD cbData = sizeof(Data);
    //枚举HKEY_CURRENT_CONFIG\Software键值项
    for (int dwIndex = 0; dwIndex < cValues ; ++dwIndex) {
        lRtn = RegEnumValue(hKey, dwIndex, szItemName, &cbItemName, 0, 0, Data, &cbData);
        if (lRtn == ERROR_SUCCESS) {
            cout << "EnumItem : " << szItemName <<" Data : "<<Data<< endl;
            cbData = sizeof(Data);  //如果是用同一数组保存Name,注意重置为cbData分配的空间大小
        }
        else{
            cout << "RegEnumValue error :  0x" << hex << lRtn << endl;
        }
    }

    RegCloseKey(hKey);  //关闭注册表句柄
    hKey = NULL;
    return 0;
}

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值