注册表操作详解

来源:互联网 发布:小米手机抢购软件神器 编辑:程序博客网 时间:2024/06/16 18:17

注册表操作详解

基础知识


注册表的组织方式跟文件目录比较相似,主要分为根键子键键值项三部分,与文件目录对应的话就是根目录子目录文件。分别介绍一下这三部分:

  1. 根键:共有5个,分别为HKEY_CLASSES_ROOT,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_USERS和HKEY_CURRENT_CONFIG,把它们理解成磁盘的五个分区可以了。
  2. 子键:可以有多个子键和键值项,就像一个目录中可以有多个子目录和多个文件一样。
  3. 键项值:可以理解为文件,它由三部分组成,分别为:名称、类型、数据。
类型又分为多种主要包括如下:    REG_BINARY 二进制数据    REG_DWORD 32位双字节数据    REG_SZ 以0结尾的字符串    REG_DWORD_BIG_ENDIAN 高位排在底位的双字    REG_EXPAND_SZ 扩展字符串,可以加入变量如%PATH%    REG_LINK UNICODE 符号链接    REG_RESOURCE_LIST 设备驱动程序资源列表    REG_MULTI_SZ 多字符串注册表数据项的数据类型有8种,但最常用的主要是前3种。

常用API


1.打开/关闭注册表

LONG WINAPI RegOpenKeyEx(  _In_        HKEY hKey,         // 父键句柄  _In_opt_    LPCTSTR lpSubKey,  // 子键的名称  _Reserved_  DWORD ulOptions,   // 保留项,传0即可  _In_        REGSAM samDesired, // 访问权限  _Out_       PHKEY phkResult    // 返回子键的句柄);

HKEY hKey——父键的句柄,可为RegCreateKeyEx或RegOpenKeyEx返回的注册表键句柄或为预定义的根键HKEY_CLASSES_ROOT,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_USERS或HKEY_CURRENT_CONFIG

REGSAM samDesired——访问权限,想方便的话可以指定为KEY_ALL_ACCESS,这样什么权限都有了。其他常用的权限还有KEY_READ,KEY_WRITE等。

成功开启子键则返回ERROR_SUCCESS

LONG WINAPI RegCloseKey(  _In_  HKEY hKey);

这两个函数需配对使用

// 打开注册表键------  HKEY hKey;  LPCTSTR lpszSubKey = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall");  int ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey);  if (ret != ERROR_SUCCESS)  {      // 打开失败      ......  }  ......  // 关闭注册表键------  RegCloseKey(hKey);

2.获取注册表键的子键及键值的信息
每个注册表键下面都包含子键及键值项,RegQueryInfoKey函数用于获取子键的数量,键值项的数量等信息。

LONG WINAPI RegQueryInfoKey(  _In_        HKEY hKey,               // 要获取信息的注册表键句柄  _Out_opt_   LPTSTR lpClass,          // 一般传NULL  _Inout_opt_ LPDWORD lpcClass,        // 一般传NULL  _Reserved_  LPDWORD lpReserved,      // NULL  _Out_opt_   LPDWORD lpcSubKeys,      // hKey下的子键数量  _Out_opt_   LPDWORD lpcMaxSubKeyLen, // hKey下的子键名称的最大长度(不包含结尾的null字符)  _Out_opt_   LPDWORD lpcMaxClassLen,  // 一般传NULL  _Out_opt_   LPDWORD lpcValues,       // hKey下的键值的数量  _Out_opt_   LPDWORD lpcMaxValueNameLen, // hKey下键值Name的最大长度(不包含结尾的null字符)  _Out_opt_   LPDWORD lpcMaxValueLen,     // hKey下的键值Data的最大长度(in bytes)  _Out_opt_   LPDWORD lpcbSecurityDescriptor, // 安全描述符长度,一般传NULL  _Out_opt_   PFILETIME lpftLastWriteTime     // 最后修改时间,一般传NULL);

通过RegQueryInfoKey获取了子键及键值项的信息后,这才知道子键的数量,键值项的数量等信息,后面就可以通过RegEnumKeyEx枚举子键信息,通过RegEnumValue枚举键值项信息。

DWORD dwSubKeyCnt;          // 子键的数量  DWORD dwSubKeyNameMaxLen;   // 子键名称的最大长度(不包含结尾的null字符)  DWORD dwKeyValueCnt;        // 键值项的数量  DWORD dwKeyValueNameMaxLen; // 键值项名称的最大长度(不包含结尾的null字符)  DWORD dwKeyValueDataMaxLen; // 键值项数据的最大长度(in bytes)  int ret = RegQueryInfoKey(      hKey,      NULL,      NULL,      NULL,      &dwSubKeyCnt,      &dwSubKeyNameMaxLen,      NULL,      &dwKeyValueCnt,      &dwKeyValueNameMaxLen,      &dwKeyValueDataMaxLen,      NULL,      NULL);  if (ret != ERROR_SUCCESS) // Error  {      ......  }  

3.枚举子键信息

LONG WINAPI RegEnumKeyEx(  _In_         HKEY hKey,  _In_         DWORD dwIndex,      // 索引,从0开始  _Out_        LPTSTR lpName,      // 接收子键的名称  _Inout_      LPDWORD lpcName,    // lpName的大小(in characters,包含null)  _Reserved_   LPDWORD lpReserved, // NULL  _Inout_      LPTSTR lpClass,     // 一般传NULL  _Inout_opt_  LPDWORD lpcClass,   // 一般传NULL  _Out_opt_    PFILETIME lpftLastWriteTime  // 一般传NULL);

前面通过RegQueryInfoKey获取了hKey下子键的数量以及子键名称的最大长度,那么接下来通过RegEnumKeyEx就可以获取每个子键的名称了。为什么要获取子键的名称,因为获取了这个名称之后,就可以通过RegOpenKeyEx开启子键获得其句柄。

整个流程差不多是这样子的:RegQueryInfoKey–>获得某注册表键下的子键的数量及子键名称的最大长度–>RegEnumKeyEx–>枚举获取每个子键的名称–>RegOpenKeyEx–>开启子键句柄–>做你想要的操作。

lpName——

前面通过RegQueryInfoKey获取了子键名称的最大长度(没有包含结尾的null字符),所有可以通过定义一个[最大长度+1]大小的Buffer来接收<br/>

lpcName——

RegQueryInfoKey获取的子键名称的最大长度 + 1
//  // 以下代码中的变量dwSubKeyNameMaxLen&dwSubKeyCnt由  // RegQueryInfoKey获取  //  LPTSTR lpszSubKeyName = new TCHAR[dwSubKeyNameMaxLen+1];  for (int index = 0; index < dwSubKeyCnt; ++index)  {      memset(lpszSubKeyName, 0, sizeof(TCHAR)*(dwSubKeyNameMaxLen+1));      DWORD dwNameCnt = dwSubKeyNameMaxLen + 1;      int ret = RegEnumKeyEx(          hKey,          index,          lpszSubKeyName,          &dwNameCnt,          NULL,          NULL,          NULL,          NULL);      if (ret != ERROR_SUCCESS)      {          ......      }  }  delete[] lpszSubKeyName;  

4.枚举键值项信息

LONG WINAPI RegEnumValue(  _In_         HKEY hKey,  _In_         DWORD dwIndex,         // 索引,从0开始  _Out_        LPTSTR lpValueName,    // 接收键值项的名称  _Inout_      LPDWORD lpcchValueName,// lpValueName的大小,包含null character  _Reserved_   LPDWORD lpReserved,    // NULL  _Out_opt_    LPDWORD lpType,        // 接收键值项的类型  _Out_opt_    LPBYTE lpData,         // 接收键值项的数据  _Inout_opt_  LPDWORD lpcbData       // lpData的Buffer大小(in bytes));

前面通过RegQueryInfoKey获取了hKey下键值项的数量以及键值项名称的最大长度,键值项数据的最大长度,那么接下来通过RegEnumValue就可以获取每个键值项的名称、类型、数据。

//  // 以下代码中变量:dwKeyValueCnt & dwKeyValueNameMaxLen &  //                dwKeyValueDataMaxLen  // 均为通过RegQueryInfoKey获取的  //  for (unsigned int index = 0; index < dwKeyValueCnt; ++index)  {      LPTSTR lpszKeyValueName = new TCHAR[dwKeyValueNameMaxLen + 1];      memset(lpszKeyValueName, 0, sizeof(TCHAR)*(dwKeyValueNameMaxLen + 1));      DWORD  dwNameCnt = dwKeyValueNameMaxLen + 1;      DWORD  dwKeyValueType;      LPBYTE lpbKeyValueData = new BYTE[dwKeyValueDataMaxLen];      DWORD  dwKeyValueDataLen;      int ret = RegEnumValue(          hKey,           index,           lpszKeyValueName,          &dwNameCnt,           NULL,           &dwKeyValueType,            lpbKeyValueData,          &dwKeyValueDataLen);      if (ret != ERROR_SUCCESS)      {          ......      }      delete[] lpszKeyValueName;      delete[] lpbKeyValueData;  }  

5.由键值项名称获取键值项的类型及键值项数据

LONG WINAPI RegQueryValueEx(  _In_         HKEY hKey,  _In_opt_     LPCTSTR lpValueName, // 键值项名称  _Reserved_   LPDWORD lpReserved,  // NULL  _Out_opt_    LPDWORD lpType,      // 接收键值项类型  _Out_opt_    LPBYTE lpData,       // 接收键值项数据  _Inout_opt_  LPDWORD lpcbData     // lpData的Buffer大小(in bytes));

有时候,我们知道某注册表键下的键值项的名称,而想获取键值项的类型及键值项数据,就可以通过该函数获取。

比如:我们知道HKEY_CURRENT_USER\Environment注册表键下存在名为”Path”的键值项,通过该函数就可以获取其值。

通常情况下,虽然我们知道键值项的名称,却不知道键值项数据的大小,也即lpData该如何定义?可以分两步实现:一、调用RegQueryValueEx,但传lpData为NULL,函数执行成功后,lpcbData会返回键值项数据的大小。二、根据上一步获取的键值项数据的大小,new一个对应大小的Buffer,然后再调用RegQueryValueEx,传递lpData为新开辟的Buffer,这样就可以了。

// 获取键值项Data的大小  LPCTSTR lpszKeyValueName = TEXT("???");  DWORD dwKeyValueType;  DWORD dwKeyValueDataSize;  int ret = RegQueryValueEx(hKey, lpszKeyValueName, NULL, &dwKeyValueType, NULL, &dwKeyValueDataSize);  if (ret != ERROR_SUCCESS)  {      ......  }  // 获取键值项Data  LPBYTE lpbKeyValueData = new BYTE[dwKeyValueDataSize];  ret = RegQueryValueEx(hKey, lpszKeyValueName, NULL, &dwKeyValueType, lpbKeyValueData, &dwKeyValueDataSize);  if (ret != ERROR_SUCCESS)  {      ......  }  delete[] lpbKeyValueData;  

6.设置键项值的值/新建键值项

LONG RegSetValueEx(  HKEY hKey,  LPCWSTR lpValueName,  DWORD Reserved,  DWORD dwType,  const BYTE* lpData,  DWORD cbData);

该函数也可以新建键值项,当lpValueName指定名称的键值项不存在时,会新建键值项。
7.删除键项值

LONG RegDeleteValue(   HKEY hKey,   LPCWSTR lpValueName ); 

8.创建、删除子键

LONG RegCreateKeyEx(   HKEY hKey,   LPCWSTR lpSubKey,   DWORD Reserved,   LPWSTR lpClass,   DWORD dwOptions,   REGSAM samDesired,   LPSECURITY_ATTRIBUTES lpSecurityAttributes,   PHKEY phkResult,   LPDWORD lpdwDisposition ); LONG WINAPI RegDeleteKey(  _In_  HKEY hKey,  _In_  LPCTSTR lpSubKey);

示例程序


示例程序一:读取注册表获取计算机上已安装程序的信息
Windows 系统中,安装程序都可以在注册表 HKEY_LOCAL_MACHINE\SoftWare\Microsoft\Windows\CurrentVersion\Uninstall 获取,并且xp、vista、win7、win8都一样

以下示例程序中:

结构体ApplicationInfoA用于记录每个安装程序的具体信息,至于为何在名称后面加A,主要是为了表明其下的信息全是用string记录的。

函数GetAllInstalledAppInfoA用于获取计算机上已安装程序的全部信息,它接受vector引用类型的参数,并将获取的全部信息存放在该vector中。该程序执行成功返回0,执行失败则返回-1。

main()函数中演示了怎么使用:

vector<ApplicationInfoA> vAppInfo;     GetAllInstalledAppInfoA(vAppInfo);

在获取了安装程序的信息后,输出到D盘下的InstalledAppInfo.txt文件中。
这里写图片描述

#include <windows.h>  #include <iostream>  #include <TCHAR.H>  #include <vector>  using namespace std;  //  // 用于记录安装软件信息的结构体  //  struct ApplicationInfoA  {      string strName;            // 软件名      string strDisplayName;     // 显示的软件名      string strPublisher;       // 发布者      string strVersion;         // 版本      string strDisplayVersion;  // 显示的版本      string strInstallLocation; // 安装的位置  };  //  // 获取具体的程序的键值Data  // hKey [in]  //     --- 指向HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall的子键句柄  // lpszKeyValueName [in]  //     --- hKey下面的子键名称  // lpszKeyValueName [in]  //     --- 正如其名,键值的名称  // strKeyValue [out]  //     --- 键值的Data  //  int _GetAppInfoA_(HKEY hKey, LPCSTR lpszAppName, LPCSTR lpszKeyValueName, string& strKeyValue)  {      int ret;      // 打开已安装软件的注册表键------------------------------------------------      HKEY hInstallAppKey;      ret = RegOpenKeyEx(hKey, lpszAppName, 0, KEY_ALL_ACCESS, &hInstallAppKey);      if (ret != ERROR_SUCCESS)      {          return -1;      }      // 获取已安装软件的注册表键的键值------------------------------------------      // 1.获取字符串大小(默认为字符串即REG_SZ)      DWORD dwKeyValueType = REG_SZ;      DWORD dwKeyValueDataSize = 0;      ret = RegQueryValueExA(          hInstallAppKey,          lpszKeyValueName,          NULL,          &dwKeyValueType,          NULL,          &dwKeyValueDataSize);      if (ret == ERROR_FILE_NOT_FOUND)      {          RegCloseKey(hInstallAppKey);          return 0;      }      else if (ret != ERROR_SUCCESS)      {          RegCloseKey(hInstallAppKey);          return -1;      }      // 2.获取字符串值      if (dwKeyValueType != REG_SZ)   // 如果不是字符串类型则返回,有的安装程序此项不为字符串而为其他类型,忽略      {          RegCloseKey(hInstallAppKey);          return 0;      }      LPSTR lpszKeyValueData = new char[dwKeyValueDataSize + 1];      memset(lpszKeyValueData, 0, dwKeyValueDataSize + 1);      ret = RegQueryValueExA(          hInstallAppKey,          lpszKeyValueName,          NULL,          &dwKeyValueType,          (LPBYTE)lpszKeyValueData,          &dwKeyValueDataSize);      if (ret != ERROR_SUCCESS)      {          delete[] lpszKeyValueData;          RegCloseKey(hInstallAppKey);          return -1;      }      strKeyValue = lpszKeyValueData;      delete[] lpszKeyValueData;      // 关闭注册表键------------------------------------------------------------      RegCloseKey(hInstallAppKey);      return 0;  }  //  // 获取系统安装的程序信息并存储于参数vector中  // 成功执行返回0  // 执行失败则返回-1  //  int GetAllInstalledAppInfoA(vector<ApplicationInfoA>& vAppInfo)  {      int ret;      // 打开注册表键------------------------------------------------------------      HKEY hKey;      LPCSTR lpszSubKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";      ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey);      if (ret != ERROR_SUCCESS)      {          return -1;      }      // 获取子键&键值信息-------------------------------------------------------      DWORD dwSubKeysCnt;           // 子键数量      DWORD dwMaxSubKeyNameLen;     // 子键名字的最大长度(not including the terminating null character)      DWORD dwKeyValueCnt;          // 键值的数量      DWORD dwMaxKeyValueNameLen;   // 键值名字的最大长度(not including the terminating null character)      DWORD dwMaxKeyValueDataLen;   // 键值数据的最大长度(in Bytes)      ret = RegQueryInfoKey(          hKey,          NULL,          NULL,          NULL,          &dwSubKeysCnt,          &dwMaxSubKeyNameLen,          NULL,          &dwKeyValueCnt,          &dwMaxKeyValueNameLen,          &dwMaxKeyValueDataLen,          NULL,          NULL);      if (ret != ERROR_SUCCESS)      {          RegCloseKey(hKey);          return -1;      }      // 枚举子键信息------------------------------------------------------------      DWORD dwIndex;      LPSTR lpszSubKeyName = new char[dwMaxSubKeyNameLen + 1];      DWORD dwNameLen = dwMaxSubKeyNameLen + 1;      for (dwIndex = 0; dwIndex < dwSubKeysCnt; ++dwIndex)      {          dwNameLen = dwMaxSubKeyNameLen + 1;          memset(lpszSubKeyName, 0, dwMaxSubKeyNameLen + 1);          ret = RegEnumKeyEx(              hKey,              dwIndex,              lpszSubKeyName,              &dwNameLen,              NULL,              NULL,              NULL,              NULL);          if (ret != ERROR_SUCCESS)          {              RegCloseKey(hKey);              delete[] lpszSubKeyName;              return -1;          }          //************获取具体的程序的安装信息BEG*************          ApplicationInfoA appInfo;          appInfo.strName = lpszSubKeyName;          _GetAppInfoA_(hKey, lpszSubKeyName, "DisplayName", appInfo.strDisplayName);          _GetAppInfoA_(hKey, lpszSubKeyName, "Publisher", appInfo.strPublisher);          _GetAppInfoA_(hKey, lpszSubKeyName, "Version", appInfo.strVersion);          _GetAppInfoA_(hKey, lpszSubKeyName, "DisplayVersion", appInfo.strDisplayVersion);          _GetAppInfoA_(hKey, lpszSubKeyName, "InstallLocation", appInfo.strInstallLocation);          vAppInfo.push_back(appInfo);          //************获取具体的程序的安装信息END*************      }      delete[] lpszSubKeyName;      // 关闭注册表键------------------------------------------------------------      RegCloseKey(hKey);      return 0;  }  int main()  {      cout << "Reg Demo Test" << endl;      vector<ApplicationInfoA> vAppInfo;      cout << GetAllInstalledAppInfoA(vAppInfo) << endl;      //输出到文件      vector<ApplicationInfoA>::iterator iter = vAppInfo.begin();      FILE *fp = fopen("D:\\InstalledAppInfo.txt", "a");      while (iter != vAppInfo.end())      {          fprintf(fp, "----------------\n");          fprintf(fp, "Name: %s\n DisplayName: %s\n Publisher: %s\n Version: %s\n DisplayVersion: %s\n InstallLocation: %s\n",               iter->strName.c_str(), iter->strDisplayName.c_str(),              iter->strPublisher.c_str(), iter->strVersion.c_str(),               iter->strDisplayVersion.c_str(), iter->strInstallLocation.c_str());          fprintf(fp, "----------------\n\n");          ++iter;      }      fclose(fp);      return 0;  }  

示例程序二:增加path环境变量
我们常常需要手工添加环境变量,如下图所示:

这里写图片描述
那么怎样用程序实现呢?环境变量的配置存储在注册表当中,可以通过读写注册表来实现读写环境变量。

系统变量存储在注册表的如下位置:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

而用户变量则存储在注册表的如下位置:HKEY_CURRENT_USER\Environment

下面示例程序用于向系统变量中的Path环境变量中增加内容。

main函数中调用AddPathEnvValue(“;HelloKitty”)就用于向Path环境变量后面添加;HelloKitty。当然程序中有防呆机制,如果系统变量下刚开始没有Path环境变量则先新增Path环境变量。程序执行成功返回0,执行失败返回-1。

代码如下:

#include <windows.h>  #include <iostream>  using namespace std;  //  // 为系统变量下的Path环境变量增加内容lpszPathValue  // 成功则返回0  // 失败则返回-1  // 若刚开始Path环境变量为"D:\\123"  // 则调用AddPathEnvValue(";HelloKitty")后为"D:\\123;HelloKitty"  //  int AddPathEnvValue(LPCSTR lpszPathValue)  {      int ret;      // 打开注册表键----------------------------------------      HKEY hKey;      LPCSTR lpszSubKey = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";      ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey);      if (ERROR_SUCCESS != ret)      {          cout << "RegOpenKeyExA():Error" << endl;          return -1;      }      // 读取注册表键的键值"Path"----------------------------      // 1.获取KeyValueData即字符串的大小      LPCSTR lpszKeyValueName = "Path";      DWORD  dwKeyValueType = REG_EXPAND_SZ;      DWORD  dwKeyValueDataSize = 0;         ret = RegQueryValueExA(hKey, lpszKeyValueName, NULL, &dwKeyValueType, NULL, &dwKeyValueDataSize);      if (ret == ERROR_FILE_NOT_FOUND)      {          //不存在Path环境变量则新增一个Path环境变量          ret = RegSetValueExA(hKey, lpszKeyValueName, 0, REG_EXPAND_SZ, (const BYTE*)"", 1);          if (ret != ERROR_SUCCESS)          {              cout << "RegSetValueExA():Error" << endl;              RegCloseKey(hKey);              return -1;          }      }      else if (ret != ERROR_SUCCESS)      {          cout << "RegQueryValueExA():Error" << endl;          RegCloseKey(hKey);          return -1;      }      else if (dwKeyValueType != REG_EXPAND_SZ)      {          cout << "It is impossible" << endl;          cout << dwKeyValueType << endl;          RegCloseKey(hKey);          return -1;      }      // 2.获取KeyValueData即字符串的值      CHAR *lpszKeyValueData = new CHAR[dwKeyValueDataSize + 1];      memset(lpszKeyValueData, 0, dwKeyValueDataSize + 1);      ret = RegQueryValueExA(hKey, lpszKeyValueName, NULL, &dwKeyValueType, (LPBYTE)lpszKeyValueData, &dwKeyValueDataSize);      if (ret != ERROR_SUCCESS)      {          cout << "RegQueryValueExA():Error" << endl;          RegCloseKey(hKey);          delete[] lpszKeyValueData;          return -1;      }      // 在原注册表键值的基础上添加新的值      unsigned int nLen = strlen(lpszPathValue);      nLen += strlen(lpszKeyValueData);      CHAR *lpszKeyValueData_New = new CHAR[nLen + 1];      memset(lpszKeyValueData_New, 0, nLen + 1);      sprintf(lpszKeyValueData_New, "%s%s", lpszKeyValueData, lpszPathValue);      ret = RegSetValueExA(hKey, lpszKeyValueName, 0, REG_EXPAND_SZ, (const BYTE*)lpszKeyValueData_New, strlen(lpszKeyValueData_New) + 1);      if (ret != ERROR_SUCCESS)      {          cout << "RegSetValueExA:Error" << endl;          RegCloseKey(hKey);          delete[] lpszKeyValueData;          delete[] lpszKeyValueData_New;          return -1;      }      delete[] lpszKeyValueData;      delete[] lpszKeyValueData_New;      // 关闭注册表键----------------------------------------      RegCloseKey(hKey);      return 0;  }  int main()  {      cout << AddPathEnvValue(";HelloKitty") << endl;      return 0;  }  



声明:参考 http://blog.csdn.net/niushitang/article/details/21653849
   更多 VC 读注册表获取安装程序、C++ 注册表编程

0 0
原创粉丝点击