Windows 注册表相关API总结

it2025-09-19  3

目录

一、注册表简介几个根键的用途说明: 二、常用API介绍1.RegCreateKeyEx() 创建注册表键关于KEY_WOW64_32KEY/KEY_WOW64_64KEY几点说明 2.RegOpenKeyEx() 打开注册表3.RegDeleteKeyEx() 删除注册表键4.RegCloseKey() 关闭注册表句柄5.RegSetValueEx() 写注册表6.RegQueryValueEx() 读注册表7.RegGetValue() 读注册表RegGetValue()较于RegQueryValueEx()优点: 8.RegEnumKeyEx() 枚举注册表子健9.RegEnumValue() 枚举键值项示例代码

一、注册表简介

注册表实际上是一个管理配置系统运行参数的核心数据库,它记录了安装软件与运行程序的关联关系,计算机的硬件配置等信息。可以说计算机上所有针对硬件、软件、网络的操作都是源于注册表的。 可以使用 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_ROOTHKEY_CURRENT_CONFIGHKEY_CURRENT_USERHKEY_LOCAL_MACHINEHKEY_USERSRegOpenKeyEx或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几点说明

只适用于64位系统,以下所说情况都是在64位系统下。在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"。如果想用32位程序访问“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft” ,需要在samDesired 添加KEY_WOW64_64KEY。同理64位程序如果想访问Wow6432Node目录,需要使用KEY_WOW64_32KEY。示例 //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\0REG_NONE 未定义的类型REG_QWORD 8字节数据REG_QWORD_LITTLE_ENDIAN 等同于REG_QWORDREG_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_NONERRF_RT_REG_QWORD 仅允许 REG_QWORDRRF_RT_REG_SZ仅允许 REG_SZRRF_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; }

未完待续。。。

最新回复(0)