Win32编程之注册表的相关操作(十四)

发布时间 2023-09-20 15:11:26作者: TechNomad

一、设置注册表项的值

RegOpenKeyEx函数

RegOpenKeyEx 函数是 Windows API 中的一个函数,用于打开注册表中的一个指定注册表项的句柄。通过该句柄,您可以读取或修改该注册表项中的值和子项。

函数原型:

LONG RegOpenKeyEx(
  HKEY   hKey,         // 指定基本注册表项的句柄
  LPCTSTR lpSubKey,    // 指定要打开的注册表子项的名称
  DWORD  ulOptions,    // 保留参数,通常为 0
  REGSAM samDesired,   // 指定对注册表项的访问权限
  PHKEY  phkResult     // 接收打开的注册表项的句柄
);

参数解释:

  • hKey:指定一个基本注册表项的句柄,它是一个 HKEY 类型的句柄,用于指定在哪个根注册表项下打开子项。常用的根注册表项包括 HKEY_LOCAL_MACHINEHKEY_CURRENT_USER 等。
  • lpSubKey:指定要打开的注册表子项的名称。这是一个以 null 结尾的字符串。
  • ulOptions:保留参数,通常为 0。
  • samDesired:指定对注册表项的访问权限,通常使用 KEY_READ 或 KEY_WRITE。您可以使用不同的访问权限标志来控制读取、写入和修改注册表的权限。
  • phkResult:指向 HKEY 类型的指针,用于接收打开的注册表项的句柄。

返回值:

  • 如果函数调用成功,返回 ERROR_SUCCESS(0),并且 phkResult 包含打开的注册表项的句柄。
  • 如果函数调用失败,返回一个非零的错误代码,可以使用 FormatMessage 函数来获取错误信息。

函数功能:

RegOpenKeyEx 函数用于打开指定注册表项的句柄,以便对其进行读取或修改操作,通过该句柄,可以执行以下操作:

  • 使用 RegQueryValueEx 函数来读取注册表项的值。
  • 使用 RegSetValueEx 函数来设置注册表项的值。
  • 使用 RegDeleteValue 函数来删除注册表项的值。
  • 使用 RegEnumKeyEx 函数来列举子项。

RegSetValueEx函数 

RegSetValueEx 函数用于设置或创建注册表中指定键的值。通过该函数,您可以将不同类型的数据(如字符串、二进制数据、整数值等)写入到注册表中。

函数原型:

LONG RegSetValueEx(
  HKEY       hKey,         // 指定一个打开的注册表项的句柄
  LPCTSTR    lpValueName,  // 指定要设置的值的名称
  DWORD      Reserved,     // 保留参数,通常为 0
  DWORD      dwType,       // 指定值的类型,如 REG_SZ、REG_DWORD 等
  const BYTE *lpData,      // 指向数据的指针
  DWORD      cbData        // 指定数据的大小(字节数)
);

参数解释:

  • hKey:指定一个打开的注册表项的句柄,您可以使用 RegOpenKeyEx 函数来打开注册表项。
  • lpValueName:指定要设置的值的名称,它是一个以 null 结尾的字符串。
  • Reserved:保留参数,通常为 0。
  • dwType:指定要设置的值的类型,例如 REG_SZ 表示字符串类型、REG_DWORD 表示双字(DWORD)类型等。不同的类型需要使用不同的数据类型和数据格式。
  • lpData:指向要写入注册表的数据的指针,数据的格式和类型必须与 dwType 参数匹配。
  • cbData:指定数据的大小(字节数),即 lpData 缓冲区中要写入的数据的字节数。

返回值:

  • 如果函数调用成功,返回 ERROR_SUCCESS(0)。
  • 如果函数调用失败,返回一个非零的错误代码,可以使用 FormatMessage 函数来获取错误信息。

函数功能:

RegSetValueEx 函数用于设置或创建注册表中的一个特定键的值。它允许您将不同类型的数据写入到注册表中,并指定值的类型(dwType)以及数据(lpData)的格式。如果指定的键和值名称不存在,它还可以创建它们。

示例代码:

#include <Windows.h>
#include <stdio.h>

int main() {
    HKEY hKey;

    // 打开或创建注册表项 HKEY_CURRENT_USER\Software\MyApp
    LONG result = RegCreateKeyEx(
        HKEY_CURRENT_USER,
        TEXT("Software\\MyApp"),
        0,
        NULL,
        REG_OPTION_NON_VOLATILE,  // 表示注册表项将在系统重启后保留
        KEY_WRITE,
        NULL,
        &hKey,
        NULL
    );

    if (result == ERROR_SUCCESS) {
        const WCHAR* valueName = TEXT("MyValue");
        const char* valueData = "Hello, Registry!";

        // 设置字符串值
        result = RegSetValueEx(
            hKey,
            valueName,
            0,
            REG_SZ,
            (BYTE*)valueData,
            strlen(valueData) + 1  // 包括 null 终止符的大小
        );

        if (result == ERROR_SUCCESS) {
            printf("Registry value set successfully.\n");
        }
        else {
            printf("Failed to set registry value.\n");
        }

        // 关闭注册表项句柄
        RegCloseKey(hKey);
    }
    else {
        printf("Failed to open or create registry key.\n");
    }

    return 0;
}

二、读取注册表项的值

RegQueryValueEx函数

RegQueryValueEx 函数用于读取注册表中指定键的值。通过该函数,您可以检索注册表项中的字符串、二进制数据、整数值等不同类型的数据

函数原型:

LONG RegQueryValueEx(
  HKEY    hKey,           // 指定一个打开的注册表项的句柄
  LPCTSTR lpValueName,    // 指定要检索的值的名称
  LPDWORD lpReserved,     // 保留参数,通常为 NULL
  LPDWORD lpType,         // 用于接收值的类型
  LPBYTE  lpData,         // 用于接收值数据的缓冲区
  LPDWORD lpcbData        // 指定缓冲区大小,接收数据的字节数
);

参数解释:

  • hKey:指定一个打开的注册表项的句柄,您可以使用 RegOpenKeyEx 函数来打开注册表项。
  • lpValueName:指定要检索的值的名称,它是一个以 null 结尾的字符串。
  • lpReserved:保留参数,通常为 NULL
  • lpType:一个指向 DWORD 类型的变量的指针,用于接收值的类型,例如 REG_SZREG_DWORD 等。
  • lpData:一个指向缓冲区的指针,用于接收检索到的值的数据。
  • lpcbData:一个指向 DWORD 类型的变量的指针,用于指定 lpData 缓冲区的大小,以接收检索到的数据的字节数。

返回值:

  • 如果函数调用成功,返回 ERROR_SUCCESS(0),并且 lpData 缓冲区中包含检索到的数据。
  • 如果函数调用失败,返回一个非零的错误代码,可以使用 FormatMessage 函数来获取错误信息。

函数功能:

RegQueryValueEx 函数用于从指定的注册表项中读取一个特定值的数据。它根据提供的注册表键和值的名称,将相应的数据检索到 lpData 缓冲区中,并通过 lpType 指针返回数据的类型。此函数可以用于读取字符串、二进制数据、整数等不同类型的值。

示例代码:

#include <Windows.h>
#include <stdio.h>

int main() {
    HKEY hKey;
    DWORD dwType;
    DWORD dwSize = MAX_PATH;
    char value[MAX_PATH];

    // 打开注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
    LONG result = RegOpenKeyEx(
        HKEY_CURRENT_USER,
        TEXT("Software\\MyApp"),
        0,
        KEY_READ,
        &hKey
    );

    if (result == ERROR_SUCCESS) {
        // 读取注册表项的 "MyValue" 值
        result = RegQueryValueEx(
            hKey,
            TEXT("MyValue"),
            NULL,
            &dwType,
            (LPBYTE)value,
            &dwSize
        );

        if (result == ERROR_SUCCESS && dwType == REG_SZ) {
            printf("Program Files Directory: %s\n", value);
        }
        else {
            printf("Failed to read registry value.\n");
        }

        // 关闭注册表项句柄
        RegCloseKey(hKey);
    }
    else {
        printf("Failed to open registry key.\n");
    }

    return 0;
}

三、删除注册表项的值

RegDeleteValue函数

RegDeleteValue 函数用于删除注册表中指定键的特定值。通过该函数,您可以删除注册表中的一个值,以清除不再需要的注册表数据  

函数原型:

LONG RegDeleteValue(
  HKEY    hKey,         // 指定一个打开的注册表项的句柄
  LPCTSTR lpValueName   // 指定要删除的值的名称
);

参数解释:

  • hKey:指定一个打开的注册表项的句柄,您可以使用 RegOpenKeyEx 函数来打开注册表项。
  • lpValueName:指定要删除的值的名称,它是一个以 null 结尾的字符串。

返回值:

  • 如果函数调用成功,返回 ERROR_SUCCESS(0)。
  • 如果函数调用失败,返回一个非零的错误代码,可以使用 FormatMessage 函数来获取错误信息。

示例代码:

#include <Windows.h>
#include <stdio.h>

int main() {
    HKEY hKey;

    // 打开注册表项 HKEY_CURRENT_USER\Software\MyApp
    LONG result = RegOpenKeyEx(
        HKEY_CURRENT_USER,
        TEXT("Software\\MyApp"),
        0,
        KEY_WRITE,
        &hKey
    );

    if (result == ERROR_SUCCESS) {
        const TCHAR* valueName = TEXT("MyValue");

        // 删除指定值
        result = RegDeleteValue(hKey, valueName);

        if (result == ERROR_SUCCESS) {
            printf("Registry value deleted successfully.\n");
        }
        else if (result == ERROR_FILE_NOT_FOUND) {
            printf("Registry value not found.\n");
        }
        else {
            printf("Failed to delete registry value.\n");
        }

        // 关闭注册表项句柄
        RegCloseKey(hKey);
    }
    else {
        printf("Failed to open registry key.\n");
    }

    return 0;
}

四、列举指定注册表键下的子键(子项)的名称

RegEnumKeyEx函数

RegEnumKeyEx 函数是用于列举指定注册表键下的子键(子项)的名称。通过该函数,您可以获取注册表项的子项列表,以便进一步处理或检查

函数原型:

LONG RegEnumKeyEx(
  HKEY       hKey,            // 指定一个打开的注册表项的句柄
  DWORD      dwIndex,         // 指定要检索的子项的索引
  LPTSTR     lpName,          // 用于接收子项名称的缓冲区
  LPDWORD    lpcName,         // 接收子项名称的缓冲区大小(字符数)
  LPDWORD    lpReserved,      // 保留参数,通常为 NULL
  LPTSTR     lpClass,         // 用于接收子项的类名称的缓冲区
  LPDWORD    lpcClass,        // 接收类名称的缓冲区大小(字符数)
  PFILETIME  lpftLastWriteTime // 接收子项的最后写入时间
);

参数解释:

  • hKey:指定一个打开的注册表项的句柄,您可以使用 RegOpenKeyEx 函数来打开注册表项。
  • dwIndex:指定要检索的子项的索引,从 0 开始计数。
  • lpName:指向接收子项名称的缓冲区的指针。
  • lpcName:指向一个 DWORD 类型的变量的指针,用于指定 lpName 缓冲区的大小(字符数)。
  • lpReserved:保留参数,通常为 NULL
  • lpClass:指向接收子项的类名称的缓冲区的指针。可以为 NULL
  • lpcClass:指向一个 DWORD 类型的变量的指针,用于指定 lpClass 缓冲区的大小(字符数)。
  • lpftLastWriteTime:指向 FILETIME 结构的指针,用于接收子项的最后写入时间。可以为 NULL

返回值:

  • 如果函数调用成功,返回 ERROR_SUCCESS(0)。
  • 如果函数调用失败,返回一个非零的错误代码,可以使用 FormatMessage 函数来获取错误信息。

示例代码:

#include <Windows.h>
#include <stdio.h>

int main() {
    HKEY hKey;
    DWORD index = 0;
    TCHAR subkeyName[MAX_PATH];
    DWORD subkeyNameSize = MAX_PATH;

    // 打开注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
    LONG result = RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
        0,
        KEY_READ,
        &hKey
    );

    if (result == ERROR_SUCCESS) {
        printf("Subkeys under HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion:\n");

        // 枚举子项名称
        while (true) {
            result = RegEnumKeyEx(
                hKey,
                index,
                subkeyName,
                &subkeyNameSize,
                NULL,
                NULL,
                NULL,
                NULL
            );

            if (result == ERROR_SUCCESS) {
                //printf("%s\n", subkeyName);
                wprintf(L"%s\n", subkeyName);
                index++;
                subkeyNameSize = MAX_PATH;
            }
            else if (result == ERROR_NO_MORE_ITEMS) {
                // 所有子项都已枚举完毕
                break;
            }
            else {
                printf("Failed to enumerate subkey.\n");
                break;
            }
        }

        // 关闭注册表项句柄
        RegCloseKey(hKey);
    }
    else {
        printf("Failed to open registry key.\n");
    }

    return 0;
}