代码改变世界

windows 注册表的编程

2013-01-12 01:29  youxin  阅读(1007)  评论(0编辑  收藏  举报

注册表(Registry,中国大陆译作注冊表,台湾、港澳译作登录档)是Microsoft Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息。早在Windows 3.0推出OLE技术的时候,注册表就已经出现。随后推出的Windows NT是第一个从系统级别广泛使用注册表的操作系统。但是,从Windows 95开始,注册表才真正成为Windows用户经常接触的内容,并在其后的操作系统中继续沿用至今。

注册表由键(或称“项”)、子键(子项)和值项构成。一个键就是分支中的一个文件夹,而子键就是这个文件夹中的子文件夹,子键同样是一个键。一个值项则是一个键的当前定义,由名称、数据类型以及分配的值组成。一个键可以有一个或多个值,每个值的名称各不相同,如果一个值的名称为空,则该值为该键的默认值。

在注册表编辑器(Regedit.exe)中,数据结构显示如下,其中,command键是open键的子键,(默认)表示该值是默认值,值名称为空,其数据类型为REG_SZ,数据值为%systemroot%\system32\NOTEPAD.EXE "%1

 

以上信息的意义是:txt类型的文件在右键菜单里的“打开”一项使用的程序是“NOTEPAD.EXE”,即用记事本打开文件。

数据类型

注册表的数据类型主要有以下五种:

显示类型(在编辑器中)数据类型说明
REG_SZ 字符串 文本字串
REG_BINARY 二进制数 二进制值,以十六进制显示。
REG_DWORD 双字 一个32位的二进制值,显示为8位的十六进制值。
REG_MULTI_SZ 多字符串 含有多个文本值的字符串
REG_EXPAND_SZ 可擴充字符串  

此外,注册表还有其他的数据类型,但是均不常用:

  • REG_DWORD_BIG_ENDIAN
  • REG_DWORD_LITTLE_ENDIAN
  • REG_FULL_RESOURCE_DESCRIPTOR
  • REG_QWORD
  • REG_FILE_NAME

注册表的分支

注册表有五个分支,下面是这五个分支的名称及作用:

名称作用
HKEY_CLASSES_ROOT 存储Windows可识别的文件类型的详细列表,以及相关联的程序
HKEY_CURRENT_USER 存储当前用户设置的信息。
HKEY_LOCAL_MACHINE 包括安装在计算机上的硬件和软件的信息
HKEY_USERS 包含使用计算机的用户的信息。
HKEY_CURRENT_CONFIG 这个分支包含计算机当前的硬件配置信息。

注册表前身

最初,Windows系统及应用程序的信息被存储在后缀名为ini的文本文件中,这就是注册表的前身。但是这么做有着致命弱点:因为每一个程序都会新安装一个或多个ini文件,来存储程序信息,导致信息的分布极为零乱;而且在16位系统下,ini文件的大小必须在64KB之内。所以ini文件被认为不便于使用和管理。

分散与集中之争

关于分散的文本文件和集中的注册表两种软件配置方式的优劣,目前仍有争论。主流操作系统中,Linux操作系统一直使用单独的文本文件来存放配置信息。而Windows平台下基于.NET框架的软件对注册表的依赖性也大大减弱。事实上,.NET软件通常使用纯文本的XML(称为app.config)文件而不是注册表进行配置,这在某种意义上是向当初的ini文本配置方式的一种回归。部分绿色软件支持者认为,集中式的注册表要求软件需要进行专门的安装步骤才可以正常运行,而单独的文本配置文件则可以不需要安装,只要将软件的文件目录拷贝过来就可以使用;当不再需要软件的时候,除删除相关文件外对于注册表也需要进行卸载步骤,才有可能不在系统中留下痕迹(很多软件即使提供了卸载步骤,仍然会留下痕迹),如果使用文本配置文件,则能做得更干净。但是,文本配置方式导致某些系统软件的配置较为困难且缺乏统一的界面(如Linux中的情况),也是不争的事实,尽管现在已经有很多软件可以方便进行系统配置,但仍存在标准不够统一的问题。

著名开源软件Fetchmail的作者Eric S. Raymond在《UNIX编程艺术》一书中有如下叙述[2]

对比terminfo数据库和Windows注册表,我们发现注册表出名地容易受到错误代码的破坏。这可能会使整个系统都无法使用。即使系统没有瘫痪,但如果破坏本身干扰了专用的注册表编辑工具,恢复工作就会很困难。

2000年以来部分恶性病毒熊猫烧香等的破坏情形看,的确存在“破坏本身干扰注册表编辑器”的问题。在某些情况下,病毒程序会监视系统进程列表,并强行关闭名为regedit的任何程序。这使得受损用户难以直接通过编辑注册表进行恢复。

via:http://zh.wikipedia.org/wiki/%E6%B3%A8%E5%86%8C%E8%A1%A8 

常用函数:

LONG WINAPI RegCreateKey(
  _In_      HKEY hKey,
  _In_opt_  LPCTSTR lpSubKey,
  _Out_     PHKEY phkResult
);

Creates the specified registry key. If the key already exists in the registry, the function opens it.

Note  This function is provided only for compatibility with 16-bit versions of Windows. Applications should use theRegCreateKeyEx function. However, applications that back up or restore system state including system files and registry hives should use the Volume Shadow Copy Service instead of the registry functions.

第一个参数是指向当前打开表项的句柄,或者是下列预定义的保留句柄值之一,实际就是注册表的几个分支:

HKEY_CLASSES_ROOT

HKEY_CURRENT_CONFIG

HKEY_CURRENT_USER

HKEY_LOCAL_MACHINE

HKEY_USERS

lpSubKey 指示当前打开或创建的表项的名称。这个表项必须是有hkey参数所标识的项的子项。

phkResult

 返回值,用来接收创建或打开的表项的句柄。当不再需要此返回的注册表项句柄时,调用RegCloseKey关闭句柄

打开间。

LONG WINAPI RegOpenKey(
  _In_      HKEY hKey,
  _In_opt_  LPCTSTR lpSubKey,
  _Out_     PHKEY phkResult
);


写入注册表
RegSetValue函数可以设置指定注册表项的默认值或者未命名值的数据。
LONG WINAPI RegSetValue(
  _In_      HKEY hKey,
  _In_opt_  LPCTSTR lpSubKey,该函数为该参数指定的子项设置默认值。如果为null,或指向空字符串。。那么函数将为hkey所指定的注册表项设置默认值。
  _In_      DWORD dwType, 值类型
  _In_      LPCTSTR lpData, 数据本身
  _In_      DWORD cbData  数据大小,单位是字节,但不包含字符串最后的空终止符。
);

 

Sets the data for the default or unnamed value of a specified registry key. The data must be a text string.

Note  This function is provided only for compatibility with 16-bit versions of Windows. Applications should use theRegSetValueEx function.

想要设置注册表项不是默认值,可以调用RegSetValueEX函数。函数原型如下:

LONG WINAPI RegSetValueEx(
  _In_        HKEY hKey,
  _In_opt_    LPCTSTR lpValueName,欲设置的值的名称
  _Reserved_  DWORD Reserved, 保留,必须为0
  _In_        DWORD dwType,
  _In_        const BYTE *lpData,
  _In_        DWORD cbData
);

 从注册表读取数据

RegQueryValue

可以读取默认值或未命名的值。

LONG WINAPI RegQueryValue(
  _In_         HKEY hKey,
  _In_opt_     LPCTSTR lpSubKey,
  _Out_opt_    LPTSTR lpValue, 返回值,用来获得与指定子项默认值相关的一个字符串。
  _Inout_opt_  PLONG lpcbValue 指定用此参数获得的buffer的大小。
);

 如果调用时,第三个参数设为null,第四个非NULL,那么该函数返回存储数据的大小。这样,可以让应用程序确定一个最佳的方式来存储获取到的数据,也就是说,程序可以根据该函数此时返回的数据长度动态地分配一块内存,用来存储将要获取到的数据,然后再去获取数据。如果在调用RegQueryValue时还不知道获取的数据的大小,可以采用这种方法,2次调用RegQueryValue,第1次获取数据长度,第2次获取值。

 

获取不是默认值(即有名称值的数据和类型),用RegQueryValueEX。

LONG WINAPI RegQueryValueEx(
  _In_         HKEY hKey,
  _In_opt_     LPCTSTR lpValueName,想要查询的值的名称,如果为null,则获取默认值。
  _Reserved_   LPDWORD lpReserved,保留,必须为null
  _Out_opt_    LPDWORD lpType,
  _Out_opt_    LPBYTE lpData,
  _Inout_opt_  LPDWORD lpcbData
);

    HKEY hKey;
    DWORD dwAge=30;
    RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",&hKey);
    RegSetValue(hKey,NULL,REG_SZ,"zhangsan",strlen("zhangsan"));//指定默认项或没名字的值
    RegSetValueEx(hKey,"age",0,REG_DWORD,(CONST BYTE*)&dwAge,4);
    RegCloseKey(hKey);

结果如下:

 

读取数据:

LONG lValue;
RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",
NULL,&lValue); 获取长度
char *pBuf=new char[lValue];
RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",
pBuf,&lValue);
MessageBox(pBuf);

 

写入整形和读取整形.

设置时不同,读取一样.

RegSetValueEx(hKey,"age",0,REG_DWORD,(CONST BYTE*)&dwAge,4);

HKEY hKey;
RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\http://www.sunxin.org\\admin",&hKey);
DWORD dwType;
DWORD dwValue;
DWORD dwAge;
RegQueryValueEx(hKey,"age",0,&dwType,(LPBYTE)&dwAge,&dwValue);
CString str;
str.Format("age=%d",dwAge);
MessageBox(str);