RegSetValueEx参数如何正确设置与使用?

99ANYc3cd6
预计阅读时长 28 分钟
位置: 首页 参数 正文

RegSetValueExWindows.h 中定义的一个核心函数,用于在注册表的指定项中设置一个值的数据,它通常与 RegCreateKeyExRegOpenKeyEx 配合使用:先用后两者打开或创建一个键(Key),然后用 RegSetValueEx 在这个键下设置或修改一个值项(Value)。


函数原型

我们来看一下函数在 C/C++ 中的完整原型:

LONG RegSetValueEx(
  [in]                HKEY       hKey,
  [in, optional]      LPCSTR     lpValueName,
  [in]                DWORD      Reserved,
  [in]                DWORD      dwType,
  [in, optional]      const BYTE *lpData,
  [in]                DWORD      cbData
);

参数详解

下面我们逐个分析每个参数的含义和用法。

hKey (输入参数)

  • 类型: HKEY (一个句柄 Handle)
  • 含义: 一个已打开的注册表项的句柄,这个句柄由 RegCreateKeyExRegOpenKeyExRegConnectRegistry 等函数返回。
  • 说明: RegSetValueEx 不会自己去寻找或创建键,它必须在一个已经打开的键句柄上操作,你可以把它想象成,你先打开了一个文件夹(得到句柄 hKey),然后在这个文件夹里创建或修改一个文件(由 lpValueName 指定)。
  • 预定义键句柄: 你可以直接使用系统预定义的根键句柄,HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER 等,但前提是你有足够的权限。

lpValueName (输入参数,可选)

  • 类型: LPCSTR (指向以 null 结尾的字符串的指针)
  • 含义: 要设置的值项的名称。
  • 说明:
    • 如果这个名称的值项已经存在,RegSetValueEx更新它的数据。
    • 如果这个名称的值项不存在RegSetValueEx创建一个新的值项。
    • 如果此参数为 NULL 或一个空字符串 (),则函数会操作该项的默认值(也称为“未命名值”或 "(Default)"),在注册表编辑器中,(默认) 旁边没有名字的那个值。
    • 注意: 此参数在 Unicode 版本的函数 RegSetValueExW 中是 LPCWSTR (宽字符)。

Reserved (输入参数)

  • 类型: DWORD
  • 含义: 保留参数,供将来使用。
  • 说明: 必须设置为 0,这是微软文档中的明确要求,传入任何其他值都可能导致函数失败或不可预期的行为。

dwType (输入参数)

  • 类型: DWORD
  • 含义: 指定要设置的数据类型。
  • 说明: 这是一个非常重要的参数,它告诉系统如何解释 lpData 指针指向的数据,你必须为你的数据选择正确的类型,常见的类型定义在 WinNT.h 中:
常量/宏 描述
REG_NONE 0 未定义的类型。
REG_SZ 1 以 null 结尾的字符串。"Hello World"
REG_EXPAND_SZ 2 以 null 结尾的字符串,其中包含未展开的环境变量路径。"%PATH%\\MyApp",系统需要用 RegGetValue 并指定 RRF_RT_REG_EXPAND_SZ 来展开它。
REG_BINARY 3 二进制数据,一个简单的字节数组。
REG_DWORD 4 32 位无符号整数。
REG_DWORD_LITTLE_ENDIAN 4 REG_DWORD 相同,用于小端字节序系统(如 x86/x64)。
REG_DWORD_BIG_ENDIAN 5 32 位无符号整数,用于大端字节序系统。
REG_LINK 6 Unicode 符号链接。
REG_MULTI_SZ 7 以 null 结尾的字符串数组,由两个 null 字符结尾。"str1\0str2\0str3\0\0"
REG_RESOURCE_LIST 8 设备驱动程序资源列表。
REG_FULL_RESOURCE_DESCRIPTOR 9 硬件设置的资源列表。
REG_RESOURCE_REQUIREMENTS_LIST 10 驱动程序资源需求列表。
REG_QWORD 11 64 位无符号整数。
REG_QWORD_LITTLE_ENDIAN 11 REG_QWORD 相同,用于小端字节序系统。

lpData (输入参数,可选)

  • 类型: const BYTE* (指向字节数组的常量指针)
  • 含义: 一个指向包含要设置数据的缓冲区的指针。
  • 说明:
    • 函数会从这个指针开始读取 cbData 字节的数据。
    • 数据的格式必须与 dwType 参数指定的类型相匹配。
    • 如果要设置的数据为空(创建一个空的 REG_SZ 字符串),可以将此参数设为 NULL,但此时 cbData 也必须为 0。
    • 注意: 即使数据是字符串(REG_SZ)或整数(REG_DWORD),也需要将其转换为字节数组(BYTE*)或指向该数据的指针,一个 int 类型的 DWORD 值,可以直接用 reinterpret_cast<BYTE*>(&myInt) 来获取指针。

cbData (输入参数)

  • 类型: DWORD
  • 含义: lpData 缓冲区中数据的字节数
  • 说明: 这是另一个关键参数,它告诉 RegSetValueEx 要从 lpData 读取多少数据。
    • 对于 REG_SZREG_EXPAND_SZ 字符串,字节数包括结尾的 null 字符 (\0),字符串 "Hello" (5个字符) 的字节数是 5 * sizeof(TCHAR) + 1 (在 ASCII 中是 6,在 Unicode 中是 11)。
    • 对于 REG_DWORD,字节数固定为 sizeof(DWORD) (通常是 4)。
    • 对于 REG_QWORD,字节数固定为 sizeof(DWORD64) (通常是 8)。
    • 对于 REG_BINARY,就是你数组中实际的字节数。
    • 对于 REG_MULTI_SZ,字节数是所有字符串(包括它们各自的 null 终止符)以及最后的额外一个 null 终止符的总和。

返回值

  • 类型: LONG
  • 含义: 函数执行的状态码。
  • 说明:
    • 如果函数成功,返回值为 ERROR_SUCCESS (定义为 0)。
    • 如果函数失败,返回值为一个非零的错误码,你可以使用 FormatMessage 函数来获取这个错误码的可读描述。

使用示例 (C++)

下面是一个完整的 C++ 示例,演示如何创建一个注册表项,并在其中设置不同类型的值。

#include <iostream>
#include <windows.h>
#include <tchar.h> // 为了使用 _T() 宏,方便在 ASCII 和 Unicode 间切换
int main() {
    // 1. 定义要操作的注册表路径
    // HKEY_CURRENT_USER\Software\MyAppSettings
    const TCHAR* subKey = _T("Software\\MyAppSettings");
    // 2. 定义要设置的值项名称和数据
    const TCHAR* szValueName = _T("MyString");
    const TCHAR* szData = _T("Hello from C++!");
    const DWORD dwData = 12345;
    const DWORD64 qwData = 12345678901234;
    const BYTE binaryData[] = { 0xDE, 0xAD, 0xBE, 0xEF };
    const TCHAR* multiSzData[] = { _T("First"), _T("Second"), _T("Third"), NULL };
    HKEY hKey = NULL;
    LONG lResult;
    // 3. 打开或创建注册表项
    // KEY_CREATE_SUBKEY | KEY_SET_VALUE 权限,则如果键不存在会创建
    lResult = RegCreateKeyEx(
        HKEY_CURRENT_USER, // 要在哪个根键下操作
        subKey,            // 子键路径
        0,                 // Reserved, 必须为0
        NULL,              // 键的类名 (通常不用)
        REG_OPTION_NON_VOLATILE, // 键是持久性的
        KEY_CREATE_SUBKEY | KEY_SET_VALUE, // 所需的访问权限
        NULL,              // 安全属性 (通常为NULL)
        &hKey,             // 输出:打开或创建的键句柄
        NULL               // 输出:指示是新建的还是已存在的 (REG_CREATED_NEW_KEY 或 REG_OPENED_EXISTING_KEY)
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("无法创建或打开注册表项,错误码: %d\n"), lResult);
        return 1;
    }
    // 4. 设置不同类型的值
    // a) 设置 REG_SZ 字符串值
    lResult = RegSetValueEx(
        hKey,
        szValueName,
        0,
        REG_SZ,
        reinterpret_cast<const BYTE*>(szData),
        (_tcslen(szData) + 1) * sizeof(TCHAR) // 包含 null 终止符
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置 REG_SZ 值失败,错误码: %d\n"), lResult);
    }
    // b) 设置 REG_DWORD 值
    lResult = RegSetValueEx(
        hKey,
        _T("MyDword"),
        0,
        REG_DWORD,
        reinterpret_cast<const BYTE*>(&dwData),
        sizeof(DWORD)
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置 REG_DWORD 值失败,错误码: %d\n"), lResult);
    }
    // c) 设置 REG_QWORD 值
    lResult = RegSetValueEx(
        hKey,
        _T("MyQword"),
        0,
        REG_QWORD,
        reinterpret_cast<const BYTE*>(&qwData),
        sizeof(DWORD64)
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置 REG_QWORD 值失败,错误码: %d\n"), lResult);
    }
    // d) 设置 REG_BINARY 值
    lResult = RegSetValueEx(
        hKey,
        _T("MyBinary"),
        0,
        REG_BINARY,
        binaryData,
        sizeof(binaryData)
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置 REG_BINARY 值失败,错误码: %d\n"), lResult);
    }
    // e) 设置 REG_MULTI_SZ 值
    DWORD cbMultiSz = 0;
    for (int i = 0; multiSzData[i] != NULL; ++i) {
        cbMultiSz += (_tcslen(multiSzData[i]) + 1) * sizeof(TCHAR);
    }
    // 加上最后一个额外的 null 终止符
    cbMultiSz += sizeof(TCHAR);
    lResult = RegSetValueEx(
        hKey,
        _T("MyMultiSz"),
        0,
        REG_MULTI_SZ,
        reinterpret_cast<const BYTE*>(multiSzData),
        cbMultiSz
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置 REG_MULTI_SZ 值失败,错误码: %d\n"), lResult);
    }
    // f) 设置默认值 (lpValueName 为 NULL)
    lResult = RegSetValueEx(
        hKey,
        NULL, // 操作默认值
        0,
        REG_SZ,
        reinterpret_cast<const BYTE*>(_T("This is the default value.")),
        (_tcslen(_T("This is the default value.")) + 1) * sizeof(TCHAR)
    );
    if (lResult != ERROR_SUCCESS) {
        _tprintf(_T("设置默认值失败,错误码: %d\n"), lResult);
    }
    // 5. 关闭注册表句柄
    RegCloseKey(hKey);
    _tprintf(_T("注册表值设置成功!\n"));
    _tprintf(_T("请在注册表中查看: HKEY_CURRENT_USER\\%s\n"), subKey);
    system("pause"); // 暂停以方便查看
    return 0;
}

重要注意事项

  1. 权限: 修改注册表需要相应的权限,对于 HKEY_CURRENT_USER,当前用户通常有完全控制权,但对于 HKEY_LOCAL_MACHINE,普通用户可能需要管理员权限。
  2. 错误处理: 总是检查 RegSetValueEx 的返回值,不要假设它会成功。
  3. 数据类型匹配: 确保 dwTypelpData/cbData 的组合是正确的,不要试图将一个字符串指针传给 REG_DWORD 类型的参数。
  4. 字节序: 在 Windows 上,REG_DWORDREG_DWORD_LITTLE_ENDIAN 是等价的,你几乎总是使用 REG_DWORD
  5. 安全: 在 64 位 Windows 上,32 位应用程序访问的注册表位置会有重定向(Wow6432Node),如果你的应用程序需要同时支持 32 位和 64 位,需要注意这一点,使用 KEY_WOW64_64KEYKEY_WOW64_32KEY 标志可以控制访问的视图。
  6. 清理: 操作完成后,务必调用 RegCloseKey 来关闭打开的键句柄,避免资源泄漏。
-- 展开阅读全文 --
头像
MacBook Air 14拆机图解,内部设计有何亮点?
« 上一篇 今天
电信cdma 智能手机
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]