编程接口(Win32 API)
开发者可通过以下核心 API 操作注册表:
RegOpenKeyEx--- 打开键RegCreateKeyEx--- 创建键RegQueryValueEx--- 读取值RegSetValueEx--- 写入值RegDeleteValue---删除项RegCloseKey--- 关闭键
在 .NET 中,可使用Microsoft.Win32.Registry和RegistryKey类进行操作。
方法详解
RegOpenKeyEx 函数(winreg.h)
LSTATUS RegOpenKeyEx(
[in] HKEY hKey,
// HKEY_CLASSES_ROOT
// HKEY_CURRENT_CONFIG
// HKEY_CURRENT_USER
// HKEY_LOCAL_MACHINE
// HKEY_USERS
[in, optional] LPCSTR lpSubKey,
// 要打开的注册表子项的名称(不区分大小写)
[in] DWORD ulOptions,
// 指定打开键时要应用的选项
// 0
// REG_OPTION_OPEN_LINK 密钥是符号链接(一般非必要)
[in] REGSAM samDesired,
// 一个掩码,指定要打开的密钥的所需访问权限
// KEY_*
[out] PHKEY phkResult
// 指向接收已打开键句柄的变量的指针
);
RegCreateKeyEx 函数 (winreg.h)
LSTATUS RegCreateKeyEx(
[in] HKEY hKey,
[in] LPCSTR lpSubKey,
DWORD Reserved,
// 保留的,必须为零
[in, optional] LPSTR lpClass,
// 此键的用户定义类类型。 可以忽略此参数。 此参数可以 **NULL**。
[in] DWORD dwOptions,
// REG_OPTION_BACKUP_RESTORE 0x00000004L 如果设置了此标志,该函数将忽略 _samDesired_ 参数,并尝试使用备份或还原密钥所需的访问权限打开密钥。
// ?REG_OPTION_CREATE_LINK(非必要) 0x00000002L 此键是符号链接。 目标路径分配给键的 L"SymbolicLinkValue"值。 目标路径必须是绝对注册表路径。
// !REG_OPTION_NON_VOLATILE 0x00000000L 此键不可变;这是默认值。 信息存储在文件中,并在重新启动系统时保留。
// REG_OPTION_VOLATILE 0x00000001L 函数创建的所有键都是可变的。 信息存储在内存中,在卸载相应的注册表配置单元时不会保留。
[in] REGSAM samDesired,
// 一个掩码,指定要创建的密钥的访问权限。
[in, optional] const LPSECURITY_ATTRIBUTES lpSecurityAttributes,
// 指向 SECURITY_ATTRIBUTES 结构的指针,该结构确定返回的句柄是否可以由子进程继承。
[out] PHKEY phkResult,
// 指向接收已打开或创建的键句柄的变量的指针。
[out, optional] LPDWORD lpdwDisposition
// 指向接收以下处置值之一的变量的指针。
// REG_CREATED_NEW_KEY 0x00000001L 密钥不存在且已创建。
// REG_OPENED_EXISTING_KEY 0x00000002L 密钥已存在,并且只是打开而不更改。
);
RegQueryValueEx 函数 (winreg.h)
LSTATUS RegQueryValueEx(
[in] HKEY hKey,
[in, optional] LPCSTR lpValueName,
LPDWORD lpReserved,
[out, optional] LPDWORD lpType,
// 指向变量的指针,该变量接收指示存储在指定值中的**数据类型**的代码。
[out, optional] LPBYTE lpData,
// 指向接收值数据的缓冲区的指针。 如果不需要数据,此参数可以为 NULL 。
[in, out, optional] LPDWORD lpcbData
// 指向变量的指针,该变量指定 lpData 参数指向的缓冲区的大小(以字节为单位)。 当函数返回时,此变量包含复制到 lpData 的数据的大小。
);
RegGetValue 函数 (winreg.h)
LSTATUS RegGetValue(
[in] HKEY hkey,
[in, optional] LPCSTR lpSubKey,
[in, optional] LPCSTR lpValue,
[in, optional] DWORD dwFlags,
// RRF_*
[out, optional] LPDWORD pdwType,
[out, optional] PVOID pvData,
[in, out, optional] LPDWORD pcbData
);
RegSetValueEx 函数 (winreg.h)
LSTATUS RegSetValueEx(
[in] HKEY hKey,
[in, optional] LPCSTR lpValueName,
DWORD Reserved,
[in] DWORD dwType,
// REG_*
[in] const BYTE *lpData,
[in] DWORD cbData
);
RegDeleteValue 函数 (winreg.h)
LSTATUS RegDeleteValue(
[in] HKEY hKey,
[in, optional] LPCSTR lpValueName
);
RegCloseKey 函数 (winreg.h)
LSTATUS RegCloseKey(
[in] HKEY hKey
);
案例
#include <windows.h>
#include <stdio.h>
int main()
{
HKEY hKey = NULL;
DWORD dwDisposition = 0; // 接收创建结果:新建 or 已存在
DWORD dwData = 0;
DWORD dwBufferSize = 0;
DWORD dwType = 0;
LONG lResult = 0;
// 目标路径:HKCU\Software\MyAppDemo\Settings
LPCWSTR subKey = L"Software\\MyAppDemo\\Settings";
// ============================================================
// 步骤 1:RegCreateKeyEx --- 创建(或打开)键
// ============================================================
// 如果键不存在则创建;如果已存在则直接打开。
// 最后一个参数接收 "REG_CREATED_NEW_KEY" 或 "REG_OPENED_EXISTING_KEY"。
lResult = RegCreateKeyExW(
HKEY_CURRENT_USER, // [in] 根键
subKey, // [in] 子键路径
0, // [in] 保留,必须为 0
NULL, // [in] 类名(可选)
REG_OPTION_NON_VOLATILE, // [in] 持久化存储(重启后保留)
KEY_ALL_ACCESS, // [in] 访问权限
NULL, // [in] 安全属性(NULL = 默认)
&hKey, // [out] 返回的键句柄
&dwDisposition // [out] 新建 or 已打开
);
if (lResult != ERROR_SUCCESS) {
wprintf(L"创建键失败,错误码: %ld\n", lResult);
return 1;
}
if (dwDisposition == REG_CREATED_NEW_KEY)
wprintf(L"✓ 键已创建: %s\n", subKey);
else
wprintf(L"✓ 键已存在,已打开: %s\n", subKey);
// ============================================================
// 步骤 2:RegSetValueEx --- 写入值
// ============================================================
// 写入一个 REG_DWORD 类型的值
DWORD dwValue = 42;
lResult = RegSetValueExW(
hKey, // [in] 已打开的键句柄
L"UserAge", // [in] 值名称
0, // [in] 保留,必须为 0
REG_DWORD, // [in] 数据类型
(const BYTE*)&dwValue, // [in] 指向数据的指针
sizeof(DWORD) // [in] 数据大小(字节)
);
if (lResult != ERROR_SUCCESS) {
wprintf(L"写入 DWORD 值失败,错误码: %ld\n", lResult);
} else {
wprintf(L"✓ 已写入 REG_DWORD: UserAge = %lu\n", dwValue);
}
// 写入一个 REG_SZ 类型的字符串值
const wchar_t* szAppName = L"我的演示程序 v1.0";
lResult = RegSetValueExW(
hKey,
L"AppName",
0,
REG_SZ,
(const BYTE*)szAppName,
(DWORD)((wcslen(szAppName) + 1) * sizeof(wchar_t)) // 包含终止符 '\0'
);
if (lResult == ERROR_SUCCESS)
wprintf(L"✓ 已写入 REG_SZ: AppName = %s\n", szAppName);
// ============================================================
// 步骤 3:RegCloseKey --- 关闭键(释放句柄)
// ============================================================
RegCloseKey(hKey);
wprintf(L"✓ 键已关闭\n\n");
// ============================================================
// 步骤 4:RegOpenKeyEx --- 打开已有键(只读方式)
// ============================================================
// 与 RegCreateKeyEx 不同,RegOpenKeyEx 在键不存在时直接返回错误。
lResult = RegOpenKeyExW(
HKEY_CURRENT_USER, // [in] 根键
subKey, // [in] 子键路径
0, // [in] 选项,通常为 0
KEY_READ, // [in] 只读访问权限
&hKey // [out] 返回的键句柄
);
if (lResult != ERROR_SUCCESS) {
wprintf(L"打开键失败,错误码: %ld\n", lResult);
return 1;
}
wprintf(L"✓ 已重新打开键(只读模式)\n");
// ============================================================
// 步骤 5:RegQueryValueEx --- 读取值
// ============================================================
// --- 5a. 读取 REG_DWORD ---
dwData = 0;
dwBufferSize = sizeof(DWORD);
lResult = RegQueryValueExW(
hKey, // [in] 已打开的键句柄
L"UserAge", // [in] 值名称
NULL, // [in] 保留
&dwType, // [out] 接收实际数据类型
(LPBYTE)&dwData, // [out] 接收数据
&dwBufferSize // [in/out] 缓冲区大小
);
if (lResult == ERROR_SUCCESS) {
wprintf(L"✓ 读取 REG_DWORD: UserAge = %lu (类型=0x%lX)\n",
dwData, dwType);
} else {
wprintf(L"读取 UserAge 失败,错误码: %ld\n", lResult);
}
// --- 5b. 读取 REG_SZ ---
wchar_t szBuffer[256] = {0};
dwBufferSize = sizeof(szBuffer);
lResult = RegQueryValueExW(
hKey,
L"AppName",
NULL,
&dwType,
(LPBYTE)szBuffer,
&dwBufferSize
);
if (lResult == ERROR_SUCCESS) {
wprintf(L"✓ 读取 REG_SZ: AppName = %s (类型=0x%lX)\n",
szBuffer, dwType);
} else {
wprintf(L"读取 AppName 失败,错误码: %ld\n", lResult);
}
// ============================================================
// 步骤 6:RegCloseKey --- 最终关闭
// ============================================================
RegCloseKey(hKey);
wprintf(L"\n✓ 所有操作完成,键已关闭。\n");
return 0;
}
注意事项
samDesired参数
| 价值 | 意义 |
|---|---|
| KEY_ALL_ACCESS(0xF003F) | 合并STANDARD_RIGHTS_REQUIRED、KEY_QUERY_VALUE、KEY_SET_VALUE、KEY_CREATE_SUB_KEY、KEY_ENUMERATE_SUB_KEYS、KEY_NOTIFY和KEY_CREATE_LINK访问权限。 |
| KEY_CREATE_LINK(0x0020) | 保留供系统使用。 |
| KEY_CREATE_SUB_KEY(0x0004) | 创建注册表项的子项是必需的。 |
| KEY_ENUMERATE_SUB_KEYS (0x0008) | 枚举注册表项的子项是必需的。 |
| KEY_EXECUTE(0x20019) | 等效于KEY_READ。 |
| KEY_NOTIFY(0x0010) | 请求注册表项或注册表项子项的更改通知所必需的。 |
| KEY_QUERY_VALUE (0x0001) | 查询注册表项的值所必需的。 |
| KEY_READ(0x20019) | 合并STANDARD_RIGHTS_READ、KEY_QUERY_VALUE、KEY_ENUMERATE_SUB_KEYS和KEY_NOTIFY值。 |
| KEY_SET_VALUE(0x0002) | 创建、删除或设置注册表值所必需的。 |
| KEY_WOW64_32KEY(0x0200) | 指示 64 位 Windows 上的应用程序应在 32 位注册表视图中运行。 32 位 Windows 忽略此标志。 有关详细信息,请参阅 访问备用注册表视图。 此标志必须与此表中查询或访问注册表值的其他标志结合使用 OR 运算符。 Windows 2000:不支持 此标志。 |
| KEY_WOW64_64KEY(0x0100) | 指示 64 位 Windows 上的应用程序应在 64 位注册表视图中运行。 32 位 Windows 忽略此标志。 有关详细信息,请参阅 访问备用注册表视图。 此标志必须与此表中查询或访问注册表值的其他标志结合使用 OR 运算符。 Windows 2000:不支持 此标志。 |
| KEY_WRITE(0x20006) | 合并STANDARD_RIGHTS_WRITE、KEY_SET_VALUE和KEY_CREATE_SUB_KEY访问权限。 |
其他(win32 标准访问权限):
| 参数 | 意义 |
|---|---|
STANDARD_RIGHTS_ALL |
合并 DELETE、READ_CONTROL、WRITE_DAC、WRITE_OWNER 和 SYNCHRONIZE 访问。 |
STANDARD_RIGHTS_EXECUTE |
当前定义为等于READ_CONTROL。 |
| 标准读取权限 (STANDARD_RIGHTS_READ) | 当前定义为等于READ_CONTROL。 |
STANDARD_RIGHTS_REQUIRED(标准权限必要) |
合并 DELETE、READ_CONTROL、WRITE_DAC 和WRITE_OWNER访问。 |
标准写入权限(STANDARD_RIGHTS_WRITE) |
当前定义为等于READ_CONTROL。 |
参考链接
微软文档-关于注册表 - Win32 apps | Microsoft Learn