注册表操作详解
基础知识
注册表的组织方式跟文件目录比较相似,主要分为根键、子键和键值项三部分,与文件目录对应的话就是根目录、子目录和文件。分别介绍一下这三部分:
- 根键:共有5个,分别为HKEY_CLASSES_ROOT,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_USERS和HKEY_CURRENT_CONFIG,把它们理解成磁盘的五个分区可以了。
- 子键:可以有多个子键和键值项,就像一个目录中可以有多个子目录和多个文件一样。
- 键项值:可以理解为文件,它由三部分组成,分别为:名称、类型、数据。
类型又分为多种主要包括如下:
REG_BINARY 二进制数据
REG_DWORD 32位双字节数据
REG_SZ 以0结尾的字符串
REG_DWORD_BIG_ENDIAN 高位排在底位的双字
REG_EXPAND_SZ 扩展字符串,可以加入变量如%PATH%
REG_LINK UNICODE 符号链接
REG_RESOURCE_LIST 设备驱动程序资源列表
REG_MULTI_SZ 多字符串
注册表数据项的数据类型有8种,但最常用的主要是前3种。
常用API
1.打开/关闭注册表
LONG WINAPI RegOpenKeyEx(
_In_ HKEY hKey, // 父键句柄
_In_opt_ LPCTSTR lpSubKey, // 子键的名称
_Reserved_ DWORD ulOptions, // 保留项,传0即可
_In_ REGSAM samDesired, // 访问权限
_Out_ PHKEY phkResult // 返回子键的句柄
);
HKEY hKey——父键的句柄,可为RegCreateKeyEx或RegOpenKeyEx返回的注册表键句柄或为预定义的根键HKEY_CLASSES_ROOT,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_USERS或HKEY_CURRENT_CONFIG
REGSAM samDesired——访问权限,想方便的话可以指定为KEY_ALL_ACCESS,这样什么权限都有了。其他常用的权限还有KEY_READ,KEY_WRITE等。
成功开启子键则返回ERROR_SUCCESS
LONG WINAPI RegCloseKey(
_In_ HKEY hKey
);
这两个函数需配对使用
// 打开注册表键------
HKEY hKey;
LPCTSTR lpszSubKey = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
int ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey);
if (ret != ERROR_SUCCESS)
{
// 打开失败
......
}
......
// 关闭注册表键------
RegCloseKey(hKey);
2.获取注册表键的子键及键值的信息
每个注册表键下面都包含子键及键值项,RegQueryInfoKey函数用于获取子键的数量,键值项的数量等信息。
LONG WINAPI RegQueryInfoKey(
_In_ HKEY hKey, // 要获取信息的注册表键句柄
_Out_opt_ LPTSTR lpClass, // 一般传NULL
_Inout_opt_ LPDWORD lpcClass, // 一般传NULL
_Reserved_ LPDWORD lpReserved, // NULL
_Out_opt_ LPDWORD lpcSubKeys, // hKey下的子键数量
_Out_opt_ LPDWORD lpcMaxSubKeyLen, // hKey下的子键名称的最大长度(不包含结尾的null字符)
_Out_opt_ LPDWORD lpcMaxClassLen, // 一般传NULL
_Out_opt_ LPDWORD lpcValues, // hKey下的键值的数量
_Out_opt_ LPDWORD lpcMaxValueNameLen, // hKey下键值Name的最大长度(不包含结尾的null字符)
_Out_opt_ LPDWORD lpcMaxValueLen, // hKey下的键值Data的最大长度(in bytes)
_Out_opt_ LPDWORD lpcbSecurityDescriptor, // 安全描述符长度,一般传NULL
_Out_opt_ PFILETIME lpftLastWriteTime // 最后修改时间,一般传NULL
);
通过RegQueryInfoKey获取了子键及键值项的信息后,这才知道子键的数量,键值项的数量等信息,后面就可以通过RegEnumKeyEx枚举子键信息,通过RegEnumValue枚举键值项信息。
DWORD dwSubKeyCnt; // 子键的数量
DWORD dwSubKeyNameMaxLen; // 子键名称的最大长度(不包含结尾的null字符)
DWORD dwKeyValueCnt; // 键值项的数量
DWORD dwKeyValueNameMaxLen; // 键值项名称的最大长度(不包含结尾的null字符)
DWORD dwKeyValueDataMaxLen; // 键值项数据的最大长度(in bytes)
int ret = RegQueryInfoKey(
hKey,
NULL,
NULL,
NULL,
&dwSubKeyCnt,
&dwSubKeyNameMaxLen,
NULL,
&dwKeyValueCnt,
&dwKeyValueNameMaxLen,
&dwKeyValueDataMaxLen,
NULL,
NULL);
if (ret != ERROR_SUCCESS) // Error
{
......
}
3.枚举子键信息
LONG WINAPI RegEnumKeyEx(
_In_ HKEY hKey,
_In_ DWORD dwIndex, // 索引,从0开始
_Out_ LPTSTR lpName, // 接收子键的名称
_Inout_ LPDWORD lpcName, // lpName的大小(in characters,包含null)
_Reserved_ LPDWORD lpReserved, // NULL
_Inout_ LPTSTR lpClass, // 一般传NULL
_Inout_opt_ LPDWORD lpcClass, // 一般传NULL
_Out_opt_ PFILETIME lpftLastWriteTime // 一般传NULL
);
前面通过RegQueryInfoKey获取了hKey下子键的数量以及子键名称的最大长度,那么接下来通过RegEnumKeyEx就可以获取每个子键的名称了。为什么要获取子键的名称,因为获取了这个名称之后,就可以通过RegOpenKeyEx开启子键获得其句柄。
整个流程差不多是这样子的:RegQueryInfoKey–>获得某注册表键下的子键的数量及子键名称的最大长度–>RegEnumKeyEx–&