Registry Win32 API详解

编程接口(Win32 API)

开发者可通过以下核心 API 操作注册表:

  • RegOpenKeyEx --- 打开键
  • RegCreateKeyEx --- 创建键
  • RegQueryValueEx --- 读取值
  • RegSetValueEx --- 写入值
  • RegDeleteValue ---删除项
  • RegCloseKey --- 关闭键
    在 .NET 中,可使用 Microsoft.Win32.RegistryRegistryKey 类进行操作。

方法详解

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

微软文档-打开、创建和关闭键 - Win32 apps | Microsoft Learn

微软文档-写入和删除注册表数据 - Win32 apps | Microsoft Learn

相关推荐
defrag25721 分钟前
Win9x下用Win32程序调用Win16函数
windows
江屿风37 分钟前
C++OJ题经验总结(竞赛)5
开发语言·c++
me83244 分钟前
【Tool】Windows 计划任务 + VBScript 弹窗提醒:从零到一的完整指南
windows
zh路西法1 小时前
【玩转VLA具身智能机械臂】(三):视觉避障——从 RGB-D 点云到 MoveIt octomap 的完整落地
c++·ros2·gazebo·moveit2·ompl·octomap
2601_956121972 小时前
线性DP(入门)
c++·算法·动态规划
2601_962201722 小时前
Java进阶,集合,Colllection,常见数据结构
java·数据结构·windows
彷徨而立2 小时前
【C/C++】多线程读写普通 int 变量的一些问题
java·c语言·c++
蒸蒸yyyyzwd3 小时前
cpp web server 面试可能问题总结
c++·笔记·八股
啊啊啊啊啊!!!!3 小时前
【c++】map和set的使用
开发语言·c++