Windows API 教程(十) 注册表操作

注册表在系统中也是一个很重要的部分。通过 win + R -> regedit 可以调出系统自带的注册表编辑
regedit

可以看到系统常用的注册表有五个大类:

名称 描述
HKEY_CLASSES_ROOT 用于存储文档类型(type or classes)及其相关联的特性(如图标、打开方式等)。该类注册表中的信息常用于 Shell 和 COM 应用程序。
HKEY_CURRENT_USER 用于存储当前用户的偏好(preferences)设置。其中包括当前用户的环境变量、项目组数据、颜色、字体、网络连接、应用程序偏好。
HKEY_LOCAL_MACHINE 存储计算机的物理状态,包括总线类型数据、系统内存、已安装的硬件和软件。
HKEY_USERS 存储用于新注册用户的默认配置以及当前用户的配置。
HKEY_CURRENT_CONFIG 包含本地计算机系统的当前硬件简介信息。其中保存的信息仅描述当前硬件配置和标准配置之间的差异. 标准硬件配置的信息保存在 HKEY_LOCAL_MACHINESoftwareSystem 键之中.

HKEY_CURRENT_CONFIGHKEY_LOCAL_MACHINESystemCurrentControlSetHardware ProfilesCurrent 的别名.

更多信息,详见 注册表预定义键(Predefined Keys)

RegOpenKeyEx

打开已存在的注册表项,更多信息详见 RegOpenKeyEx On MSDN

函数原型

LONG WINAPI RegOpenKeyEx(
  _In_        HKEY hKey,        // 要打开的键的句柄
  _In_opt_    LPCTSTR lpSubKey, // 其子项
  _Reserved_  DWORD ulOptions,  // 保留位,无用,请无视
  _In_        REGSAM samDesired,// 打开权限
  _Out_       PHKEY phkResult   // 返回打开的句柄
);

参数

参数一 hKey (输入参数)
可以传入已存在的注册表句柄(HKEY类型),也可以传入默认存在的项如:HKEY_CLASSES_ROOTHKEY_CURRENT_USERHKEY_LOCAL_MACHINEHKEY_USERSHKEY_CURRENT_CONFIG

参数二 lpSubKey (输入参数、可选)

子项字符串,可不填。如果有填写的话,那么久相当于打开 “hKeylpSubKey” (参数一与参数二拼接起来) 的注册表项。

参数三 ulOptions (保留参数)

保留参数,必须填 0。

参数四 samDesired (输入参数)

打开的注册表项句柄的权限。常见如下:

权限名 描述
KEY_READ (0x20019) 读取权限
KEY_WRITE (0x20006) 写入权限
KEY_SET_VALUE (0x0002) 创建、删除或修改
KEY_QUERY_VALUE (0x0001) 查询值
KEY_CREATE_LINK (0x0020) 系统保留(无用)
KEY_CREATE_SUB_KEY (0x0004) 注册键和创建子键
KEY_ENUMERATE_SUB_KEYS (0x0008) 遍历子键
KEY_EXECUTE (0x20019) 相当于KEY_READ
KEY_NOTIFY (0x0010)
KEY_WOW64_32KEY (0x0200)
KEY_WOW64_64KEY (0x0100)
KEY_ALL_ACCESS (0xF003F) 所有权限

详细请参见 MSDN:注册表项的安全和访问权限

参数五 phkResult (输出参数)

返回输出的句柄。

返回值

成功返回 ERROR_SUCCESS 即 0,失败则返回错误码。可以使用 FormatMessage 函数读取相应错误码的信息。

RegCreateKey

创建注册表项,详见 RegCreateKey on MSDN

LONG WINAPI RegCreateKey(
  _In_      HKEY hKey,          // 创建在哪个注册表项之下
  _In_opt_  LPCTSTR lpSubKey,   // 项名
  _Out_     PHKEY phkResult     // 返回创建的句柄
);

参数

不赘述,不明的同学可以参见稍后的例子。

返回值

同 RegOpenKeyEx 的返回值描述。

创建注册表项实例

#include <windows.h>
#include <stdio.h>

void showErrorText(DWORD error_num);

int main()
{
    HKEY hKey;
    HKEY subKey;
    DWORD result;
    char sname[] = "Write some thing as you like"; // 随便写点什么

    //打开注册表, HKEY_CURRENT_USERSoftware
    result = RegOpenKeyEx(
                 HKEY_CURRENT_USER, "Software", // 打开
                 0,              // 保留参数必须填 0
                 KEY_WRITE,      // 打开权限,写入
                 &hKey           // 打开之后的句柄
             );

    if (result == ERROR_SUCCESS)
    {
        printf("open success!n");
    }
    else
    {
        printf("open failed!n");
        showErrorText(result);
    }

    // 添加注册表项, 即 HKEY_CURRENT_USERSoftwareAnywayCompany
    RegCreateKey(hKey, "AnywayCompany", &subKey);

    // 设置 HKEY_CURRENT_USERSoftwareAnywayCompanyName 的值
    result = RegSetValueEx(
                 subKey,
                 "Name",         // Name字段
                 0,              // 保留参数必须填 0
                 REG_SZ,         // 键值类型为字符串
                 (const unsigned char *)sname, // 字符串首地址
                 sizeof(sname)   // 字符串长度
             );

    if (result == ERROR_SUCCESS)
    {
        printf("set success!n");
    }
    else
    {
        printf("set failed!n");
        showErrorText(result);
    }

    //关闭注册表:
    RegCloseKey(hKey);
    // 暂停
    system("pause");
    return 0;
}

/*
 * 根据错误码输出错误信息
 */
void showErrorText(DWORD error_num)
{
    char *msg = NULL;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error_num,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 使用默认语言
        (LPSTR)&msg,
        0,
        NULL
    );

    printf("Error code %d: ", error_num);
    if (msg == NULL)
        printf("%sn", "Unknown error");
    else
        printf("%sn", msg);
}

截图:

PS:打开 HKEY_CURRENT_USER 中的项来操作是不需要管理员权限的。

RegDeleteValue

删除某个注册表项的值,更多信息详见 RegDeleteValue on MSDN

LONG WINAPI RegDeleteValue(
  _In_      HKEY hKey,          // 要删除目标注册表项的主体
  _In_opt_  LPCTSTR lpValueName // 具体要删除的值
);

删除注册表项值的实例

#include <windows.h>
#include <stdio.h>

void showErrorText(DWORD error_num);

int main()
{
    HKEY hKey;
    HKEY subKey;
    DWORD result;
    char sname[] = "Write some thing as you like"; // 随便写点什么

    //打开注册表
    result = RegOpenKeyEx(
                 // 打开 HKEY_CURRENT_USERSoftwareAnywayCompany
                 HKEY_CURRENT_USER, "Software\AnywayCompany",
                 0,              // 保留参数必须填 0
                 KEY_WRITE,      // 打开权限,写入
                 &hKey           // 打开之后的句柄
             );

    if (result == ERROR_SUCCESS)
    {
        printf("open success!n");
    }
    else
    {
        printf("open failed!n");
        showErrorText(result);
    }

    // 删除 HKEY_CURRENT_USERSoftwareAnywayCompany 下的 Name
    result = RegDeleteValue(hKey, "Name");

    if (result == ERROR_SUCCESS)
    {
        printf("delete success!n");
    }
    else
    {
        printf("delete failed!n");
        showErrorText(result);
    }

    //关闭注册表:
    RegCloseKey(hKey);
    // 暂停
    system("pause");
    return 0;
}

/*
 * 根据错误码输出错误信息
 */
void showErrorText(DWORD error_num)
{
    char *msg = NULL;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error_num,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 使用默认语言
        (LPSTR)&msg,
        0,
        NULL
    );

    printf("Error code %d: ", error_num);
    if (msg == NULL)
        printf("%sn", "Unknown error");
    else
        printf("%sn", msg);
}

RegDeleteKey

删除注册表中的某个键, RegDeleteKey on MSDN

LONG WINAPI RegDeleteKey(
  _In_  HKEY hKey,          // 要删除目标注册表项的主体
  _In_  LPCTSTR lpSubKey    // 具体要删除的键
);

删除注册表项键的实例

#include <windows.h>
#include <stdio.h>

void showErrorText(DWORD error_num);

int main()
{
    HKEY hKey;
    HKEY subKey;
    DWORD result;
    char sname[] = "Write some thing as you like"; // 随便写点什么

    //打开注册表
    result = RegOpenKeyEx(
                 // 打开 HKEY_CURRENT_USERSoftwareAnywayCompany
                 HKEY_CURRENT_USER, "Software",
                 0,              // 保留参数必须填 0
                 KEY_WRITE,      // 打开权限,写入
                 &hKey           // 打开之后的句柄
             );

    if (result == ERROR_SUCCESS)
    {
        printf("open success!n");
    }
    else
    {
        printf("open failed!n");
        showErrorText(result);
    }

    // 删除 HKEY_CURRENT_USERSoftwareAnywayCompany
    result = RegDeleteKey(hKey, "AnywayCompany");

    if (result == ERROR_SUCCESS)
    {
        printf("delete success!n");
    }
    else
    {
        printf("delete failed!n");
        showErrorText(result);
    }

    //关闭注册表:
    RegCloseKey(hKey);
    // 暂停
    system("pause");
    return 0;
}

/*
 * 根据错误码输出错误信息
 */
void showErrorText(DWORD error_num)
{
    char *msg = NULL;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error_num,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 使用默认语言
        (LPSTR)&msg,
        0,
        NULL
    );

    printf("Error code %d: ", error_num);
    if (msg == NULL)
        printf("%sn", "Unknown error");
    else
        printf("%sn", msg);
}

列举某个注册表项之下的所有子项实例

内容有些复杂,不过平常都是直接 copy 这个 RegCloseKey 函数过去用,大家知道去哪里 copy 就行了。

// 出处:http://msdn.microsoft.com/en-us/library/ms724256(v=vs.85).aspx
// QueryKey - 列举目标注册表项之下关联的子项
//     hKey - Key whose subkeys and values are to be enumerated.

#include <windows.h>
#include <stdio.h>

#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383

void QueryKey(HKEY hKey)
{
    TCHAR    achKey[MAX_KEY_LENGTH];   // buffer for subkey name
    DWORD    cbName;                   // size of name string
    TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name
    DWORD    cchClassName = MAX_PATH;  // size of class string
    DWORD    cSubKeys = 0;             // number of subkeys
    DWORD    cbMaxSubKey;              // longest subkey size
    DWORD    cchMaxClass;              // longest class string
    DWORD    cValues;              // number of values for key
    DWORD    cchMaxValue;          // longest value name
    DWORD    cbMaxValueData;       // longest value data
    DWORD    cbSecurityDescriptor; // size of security descriptor
    FILETIME ftLastWriteTime;      // last write time

    DWORD i, retCode;

    TCHAR  achValue[MAX_VALUE_NAME];
    DWORD cchValue = MAX_VALUE_NAME;

    // Get the class name and the value count.
    retCode = RegQueryInfoKey(
                  hKey,                    // key handle
                  achClass,                // buffer for class name
                  &cchClassName,           // size of class string
                  NULL,                    // reserved
                  &cSubKeys,               // number of subkeys
                  &cbMaxSubKey,            // longest subkey size
                  &cchMaxClass,            // longest class string
                  &cValues,                // number of values for this key
                  &cchMaxValue,            // longest value name
                  &cbMaxValueData,         // longest value data
                  &cbSecurityDescriptor,   // security descriptor
                  &ftLastWriteTime);       // last write time

    // Enumerate the subkeys, until RegEnumKeyEx fails.

    if (cSubKeys)
    {
        printf( "nNumber of subkeys: %dn", cSubKeys);

        for (i = 0; i < cSubKeys; i++)
        {
            cbName = MAX_KEY_LENGTH;
            retCode = RegEnumKeyEx(hKey, i,
                                   achKey,
                                   &cbName,
                                   NULL,
                                   NULL,
                                   NULL,
                                   &ftLastWriteTime);
            if (retCode == ERROR_SUCCESS)
            {
                printf(TEXT("(%d) %sn"), i + 1, achKey);
            }
        }
    }

    // Enumerate the key values.

    if (cValues)
    {
        printf( "nNumber of values: %dn", cValues);

        for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
        {
            cchValue = MAX_VALUE_NAME;
            achValue[0] = '\0';
            retCode = RegEnumValue(hKey, i,
                                   achValue,
                                   &cchValue,
                                   NULL,
                                   NULL,
                                   NULL,
                                   NULL);

            if (retCode == ERROR_SUCCESS )
            {
                printf(TEXT("(%d) %sn"), i + 1, achValue);
            }
        }
    }
}

int main(void)
{
    HKEY hTestKey;

    if ( RegOpenKeyEx(
                // 打开 HKEY_CURRENT_USERSOFTWARE\Microsoft
                HKEY_CURRENT_USER, TEXT("SOFTWARE\Microsoft"),
                0,
                KEY_READ,
                &hTestKey) == ERROR_SUCCESS
       )
    {
        // 如果打开成功, 则遍历其下的子项
        QueryKey(hTestKey);
    }

    RegCloseKey(hTestKey);

    system("pause");
}

你可能感兴趣的:

文章索引

上一讲: Windows API 教程(九) 网络编程

1 thoughts on “Windows API 教程(十) 注册表操作

  1. 博主快快更新剩余的部分吧,万分期待!!
    Windows API 教程(十一) 系统服务
    Windows API 教程(十二) 进程间通信
    Windows API 教程(十三) 进程线程同步

留下评论