WindowsXP的注册表包含了WindowsXP的系统配置、PC机的硬件配置、Win32应用程序和用户的其他设置信息。注册表和INI文件不同,它是多层次的树状数据结构,具有六个分支(根键),每个分支又由许多的键和键值组成,而每个键则代表一个特定的配置项目。
  在实际的编程工作中,我们遇到了如何在Visual
C++中对WindowsXP注册表整个树状结构信息进行访问和修改的问题,如查询和修改注册表中用户姓名和公司名称的有关信息。通过编程实践,我们实现了在Visual
C++中查询和修改系统注册表的有关信息。下面以一个实例说明具体的编程方法。
  在Visual C++
6.0或5.0环境中新建一基于对话框的工程,设置了两个命令按钮,名为“查询用户信息”和“修改用户信息”,用来查询和修改注册表中用户姓名和公司名称。这里须要指出的是,用户的信息位于系统注册表中
HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersion
的位置,键值名RegisteredOwner和RegisteredOrganization分别表示用户的姓名和用户公司的名称。
  1.查询用户信息的代码
  HKEY hKEY; //定义有关的 hKEY, 在查询结束时要关闭。
  LPCTSTR data_Set=″SOFTWARE\Microsoft\Windows
NT\CurrentVersion\″(不要告诉我不知道”\”的含义哦);
  //打开与路径 data_Set
相关的
hKEY,第一个参数为根键名称,第二个参数表。
  //表示要访问的键的位置,第三个参数必须为0,KEY_READ表示以查询的方式。
  //访问注册表,hKEY则保存此函数所打开的键的句柄。
  long ret0=(::RegOpenKeyEx(HKEY_LOCAL_MACHINE,data_Set, 0,
KEY_READ, &hKEY));
  if(ret0!=ERROR_SUCCESS) //如果无法打开hKEY,则终止程序的执行
  {MessageBox(″错误: 无法打开有关的hKEY!″);
  return;}
  //查询有关的数据 (用户姓名 owner_Get)。
  LPBYTE owner_Get=new BYTE[80];
  DWORD type_1=REG_SZ ; DWORD cbData_1=80;
  //hKEY为刚才RegOpenKeyEx()函数所打开的键的句柄,″RegisteredOwner″。
  //表示要查
询的键值名,type_1表示查询数据的类型,owner_Get保存所。
  //查询的数据,cbData_1表示预设置的数据长度。
long ret1=::RegQueryValueEx(hKEY, ″RegisteredOwner″, NULL,
  &type_1, owner_Get, &cbData_1);
  if(ret1!=ERROR_SUCCESS)
?
  MessageBox(″错误: 无法查询有关注册表信息!″);
  return;
  }
  // 查询有关的数据 (公司名 company_Get)
  LPBYTE company_Get=new BYTE [80];
  DWORD type_2=REG_SZ; DWORD cbData_2=80;
  long ret2=::RegQueryValueEx(hKEY, ″RegisteredOrganization″,
NULL,&type_2,company_Get, &cbData_2);
  if(ret2!=ERROR_SUCCESS)
  {
  MessageBox(″错误: 无法查询有关注册表信息!″);
  return;
   }
  // 将 owner_Get 和 company_Get 转换为 CString 字符串,
以便显示输出。
  CString str_owner=CString(owner_Get);
  CString str_company=CString(company_Get);
  delete[] owner_Get; delete[] company_Get;
  // 程序结束前要关闭已经打开的 hKEY。
  ::RegCloseKey(hKEY);
  ……
  这样,上述程序执行完毕,字符串str_owner和str_company则表示查询到的用户的姓名和公司的名称,在VC++中便可用对话框的方式将其显示出来。
  2. 修改用户信息的代码(注意和上述的查询代码属于不同的函数体)
  在程序中我们先显示一个对话框,要求用户输入新的用户姓名和公司名称并按确认键,将取得CString类型的有关字符串。要先将其转换为LPBYTE(即unsigned
char*)型的数据类型,以便后面的函数调用。下面是程序中用到的将CString型转换为LPBYTE的转换函数:
  LPBYTE CString_To_LPBYTE(CString str)
  {
  LPBYTE lpb=new BYTE[str.GetLength()+1];
  for(int i=0; i   lpb[str.GetLength()]=0;
  return lpb;
  }
  以下则是具体的修改注册表用户信息的代码:
  CString str_owner, str_company;
  …… //通过对话框输入新的用户信息,保存到str_owner和str_company
  //定义有关的 hKEY, 在程序的最后要关闭。
HKEY hKEY;
  LPCTSTR data_Set=″SOFTWARE\Microsoft\Windows
NT\CurrentVersion\″;
  //打开与路径 data_Set
相关的hKEY,KEY_WRITE表示以写的方式打开。
  long ret0=(::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  data_Set, 0, KEY_WRITE, &hKEY));
  if(ret0!=ERROR_SUCCESS)
  {
  MessageBox(″错误: 无法打开有关的hKEY!″);
  return;
  }
  //修改有关数据(用户姓名
owner_Set),要先将CString型转换为LPBYTE。
  LPBYTE owner_Set=CString_To_LPBYTE(str_owner);
  DWORD type_1=REG_SZ;
  DWORD cbData_1=str_owner.GetLength()+1;
  //与RegQureyValueEx()类似,hKEY表示已打开的键的句柄,″RegisteredOwner″
  //表示要访问的键值名,owner_Set表示新的键值,type_1和cbData_1表示新值。
  //的数据类型和数据长度
  long ret1=::RegSetValueEx(hKEY, ″RegisteredOwner″, NULL,
  type_1, owner_Set, cbData_1);
  if(ret1!=ERROR_SUCCESS)
  {
  MessageBox(″错误: 无法修改有关注册表信息!″);
  return;
  }
  //修改有关的数据 (公司名 company_Set)
  LPBYTE company_Set=CString_To_LPBYTE(str_company);
  DWORD type_2=REG_SZ;
  DWORD cbData_2=str_company.GetLength()+1;
  long ret2=::RegSetValueEx(hKEY, ″RegisteredOrganization″, NULL,
  type_2, company_Set, cbData_2);
  if(ret2!=ERROR_SUCCESS)
  {
  MessageBox(″错误: 无法修改有关注册表信息!″);
  return;
   }
  执行上面的修改注册表的操作后,可打开注册表查看具体的数值,可以看到已经成功地修改了有关的数据了。
  以上实例讲述了如何在VC++中访问WindowsXP的系统注册表,我们可以很方便地查询及修改注册表的任何位置的有关信息。以上的程序在Visual
C++ 6.0中调试通过(Visual C++ 5.0与之类似),且运行结果正确。

如今修改注册表成为继超频之后的又一大热点,许多CFAN通过对注册表的修改使Win98显得更加个性化,诸多报刊杂志也纷纷扯起注册表这面旗帜,令人遗憾的是,在介绍注册表修改的众多的文章中,大都以手工修改为例,极少数文章也只介绍有关修改注册表软件的用法,至于如何在程序中实现却无人提及。为此我在Visual
Studio6.0帮助文件中用Registry关键字进行搜索,在翻译软件帮助下及不断的上机实践下,我终于摸索出使用注册表接口(API)函数的一些用法,现拿出来与大家共享。
  在程序中使用注册表,不外乎创建、打开、读取、设置、删除这五个常规操作,(要想获得更详细的资料可以参考Visual
Studio6.0帮助目录中MSDN Library Visual Studio6.0|Platform SDK|Window
Base Services|General
Library|Registry条目)。下面我们就来关注这五个接口函数的用法:
  一、 创建键RegCreateKeyEx
  通过RegCreateKeyEx函数可以在注册表中创建键,如果需要创建的键已经存在了,则打开键。函数原型如下:
  LONG RegCreateKeyEx(
  HKEY hKey,
  LPCTSTR lpSubKey,
  DWORD Reserved,
  LPTSTR lpClass,
  DWORD dwOptions,
  REGSAM samDesired,
  LPSECURITY_ATTRIBUTESlpSecurityAttributes,
  PHKEY phkResult,
  LPDWORD lpdwDisposition
  );
  各参数及返回值的含义如下:
  ?hKey为主键值,可以取下面的一些数值:
  HKEY_CLASSES_ROOT、HKEY_CURRENT_CONFIG
  HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE
  HKEY_USER、HKEY_PERFORMANCE_DATA(WINNT操作系统)
  HKEY_DYN_DATA(WIN9X操作系统)
  ?参数lpSubKey为一个指向以零结尾的字符串的指针,其中包含将要创建或打开的子键的名称。子键不可以用反斜线()开始。该参数可以为NULL。
  ?Reserved保留,必须设置为0。
  ?参数lpClass一个指向包含键类型的字符串。如果该键已经存在,则忽略该参数。
  ?参数dwOptions为新创建的键设置一定的属性。可以取下面的一些数值:
  REG_OPTION_NON_VOLATILE
新创建的键为一个非短暂性的键(数据信息保存在文件中,当系统重新启动时,数据信息恢复)
  REG_OPTION_VOLATILE
新创建的键为一个短暂性的键(数据信息保存在内存中)。Windows95忽略该数值。
  REG_OPTION_BACKUP_RESTORE 仅在WINNT中支持,可以提供优先级支持。
  ?参数samDesired用来设置对键访问的权限,可以取下面的一些数值:
  KEY_CREATE_LINK 准许生成符号键
  KEY_CREATE_SUB_KEY 准许生成子键
  KEY_ENUMERATE_SUB_KEYS 准许生成枚举子键
  KEY_EXECUTE 准许进行读操作
  KEY_NOTIFY 准许更换通告
  KEY_QUERY_VALUE 准许查询子键
  KEY_ALL_ACCESS 提供完全访问,是上面数值的组合
  KEY_READ 是下面数值的组合:
  KEY_QUERY_VALUE、KEY_ENUMERATE_SUB_KEYS、KEY_NOTIFY
  KEY_SET_VALUE 准许设置子键的数值
  KEY_WRITE 是下面数值的组合:
  KEY_SET_VALUE、KEY_CREATE_SUB_KEY
  ?参数lpSecurityAttributes为一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否被子处理过程继承。如果该参数为NULL,则句柄不可以被继承。在WINNT中,该参数可以为新创建的键增加安全的描述。
  ?参数phkResult为一个指向新创建或打开的键的句柄的指针。
  ?参数lpdwDispition指明键是被创建还是被打开的,可以是下面的一些数值:
  REG_CREATE_NEW_KEY 键先前不存在,现在被创建。
  REG_OPENED_EXISTING_KEY 键先前已存在,现在被打开。
  ?返回值
如果函数调用成功,则返回ERROR_SUCCESS。否则,返回值为文件WINERROR.h中定义的一个非零的错误代码,可以通过设置FORMAT_MESSAGE_FROM_SYSTEM标识调用FormatMessage函数来获取一个对错误的总体描述。
  二、 打开一个键RegOpenKeyEx
  RegOpenKeyEx函数可以打开一个指定的键,函数原型如下:
  LONG RegOpenKeyEx(
  HKEY hkey,
  LPCTSTR lpSubKey,
  DWORD ulOption,
  REGSAM samDesired,
  PHKEY phkResult
  );
  各参数及返回值的含义如下:
  ?参数hKey的含义同RegCreateKeyEx函数中的hKey参数。
  ?参数lpSubKey为一个指向以零结尾的字符串的指针,其中包含子键的名称,可以利用反斜线()分隔不同的子键名。如果字符串为空,则根据hKey参数创建一个新的句柄。在这种情况下,并不关闭先前打开的句柄。
  ?ulOption保留,通常必须设置为0。
  ?参数samDesired的含义同RegCreateKeyEx函数中的samDesired参数。
  ?参数phkResult为一个指针,用来指向打开的键的句柄。可以通过RegCloseKey函数关闭这个句柄。
  ?返回值同RegCreateKeyEx函数的返回值。
  三、 读取键RegQueryValueEx
  通过RegQueryValueEx函数可以从一个已经打开的键中读取数据,函数原型如下:
  LONG RegQueryValueEx(
  HKEY hKey,
  LPTSTR lpValueName,
  LPDWORD lpReserved,
  LPDWORD lpType,
  LPBYTE lpData,
  LPDWORD lpcbData
  );
  各个参数及返回值的含义如下:
  ?参数hKey为当前的一个打开的键的句柄,具体数值同RegCreateKeyEx函数的hKey参数。
  ?参数lpVauleName为一个指向非空的包含查询值的名称的字符串指针。
  ?lpReserved保留,必须为NULL。
  ?参数lpType为一个指向数据类型的指针,数据类型为下列类型之一:
  REG_BINARY 二进制数据
  REG_DWORD 32位整数
  REG_DWORD_LITTLE_ENDIAN
little-endian格式的数据,例如0X12345678以(0X78 0X56 0X34
0X12)方式保存
  REG_DWORD_BIG_ENDIAN
big-endian格式的数据,例如0X12345678以(0X12 0X34 0X56 0X78)方式保存
  REG_EXPAND_SZ 一个包含未扩展环境变量的字符串
  REG_LINK 一个Unicode类型的链接
  REG_MULIT_SZ 以两个零结尾的字符串
  REG_NONE 无类型数值
  REG_RESOURCE_LIST 设备驱动资源列表
  REG_SZ
一个以零结尾的字符串根据函数使用的字符集类型的不同而设置为Unicode或ANSI类型的字符串
  ?参数lpData为一个指向保存返回值的变量的指针。如果不需要返回值,该参数可以为NULL。
  ?参数lpcbData为一个指向保存返回值长度的变量的指针。其中长度以字节为单位。如果数据类型为REG_SZ、REG_MULTI_SZ或REG_EXPAND_SZ,那么长度也包括结尾的零字符,只有在参数lpData为NULL时,参数lpcbData才可以为NULL。
  ?返回值同RegCreateKeyEx函数的返回值。
  四、 设置键值RegSetValueEx
  RegSetValueEx函数可以设置注册表中键的值,函数原型如下:
  LONG RegSetValueEx(
  HKEY hKey,
  LPCTSTR lpValueName,
  DWORD Reserved,
  DWORD dwType,
  CONST BYTE *lpData,
  DWORD cbData
  );
  各个参数及返回值的含义如下:
  ?参数hKey的含义同RegCreateKeyEx函数中的hKey参数。
  ?参数lpValueName为一个指向包含值名的字符串指针。
  ?Reserved保留,通常必须设置为0。
  ?参数dwType确定了设置的值的类型同RegQueryValueKeyEx的lyType参数。
  ?参数lpData为一个指向包含数据的缓冲区的指针。
  ?参数cbData以字节为单位,指定数据的长度。
  ?返回值同RegCreateKeyEx函数的返回值。
  五、 删除键值RegDeketeKey
  函数RegDeketeKey删除一个键及所有的子键。函数原型如下:
  LONG RegDeleteKey(
  HKEY hKey,
  LPCTSTR lpSubKEY
  );
  各个参数及返回值的含义如下:
  ?参数hKey的含义同RegCreateKeyEx函数中的hKey参数。
  ?参数lpSubKey的含义同RegCreateKeyEx函数中的lpSubKey参数。
  六、 示例
  下面我们在Visual
C++6.0或5.0环境中新建一基于对话框的工程。设置两个命令按钮,名为“查询用户信息”和“修改用户信息”,用来查询和修改注册表中的用户姓名和公司名称。需要说明的是,用户的信息位于系统注册表中KEY-CURRENT-USERSoftwareMicrsoftMS
Setup(ACME)User
Info的位置,键值名DefName和DefCompany分别表示用户的姓名和用户公司的名称。
  1、 查询用户信息的代码
  HKEY hKey; //定义有关的hKey,在查询结束时要关闭。
  LPCTSTR path=”SoftwareMicrsoftMS Setup(ACME)User Info”;
  LONG
return0=(::RegOpenKeyEx(HKEY_CURRENT_USER,path,0,KEY_READ,&hKey));
  if(return0!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法打开有关的键!”);
  Return;
  }
  LPBYTE username_Get=new BYTE[80];
  DWORD type_1=REG_SZ;
  DWORD cbData_1=80;
  LONG return1=::RegQueryValueEx(hKey,”Defname:,NULL,&type_1,
  username_Get,&cbData_1);
  if(return1!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法查询有关注册表信息!”);
  Return;
  }
  LPBYTE company_Get=new BYTE[80];
  DWORD type_2=REG_SZ;
  DWORD cbData_2=80;
  LONG return2=::RegQueryValueEx(hKey,”DefCompany”,NULL,&type_2,
  company_Get,&cbData_2);
  if(return2!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法查询有关注册表信息!”);
  Return;
  }
  //将username_Get和company_Get转换为CString字符串,以便显示输出
  CString str_username=CString(username_Get);
  CString str_company=CString(company_Get);
  delete[] username_Get;
  delete[] company_Get;
  //程序结束前关闭已经打开的hKey
  ::RegCloseKey(hKey);
  ……
  字符串str_username和str_company表示查询的用户的姓名和公司的名称。
  2、修改用户信息的代码
  因用户输出的是CString类型的字符串,要先将其转换为LPBYTE类型,以便以后函数的调用。下面是转换函数:
  LPBYTE CString_To_LPBYTE(CString str)
  {
  LPBYTE lpb=new BYTE [str.GetLength( )+1];
  for(int i=0;i   lpb[str.GetLength( )]=0;
  return lpb;
  }
  以下是具体的修改注册表用户信息的代码:
  CString str_username,str_company;
  HKEY hKey;
  LPCTSTR path=“SoftwareMicrsoftMS Setup(ACME)User Info”;
  LONG
return0(::RegOpenKeyEx(HKEY_CURRENT_USER,path,0,KEY_WRITE,&hKey));
  if(return0!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法打开有关的键!”);
  return;
  }
  LPBYTE username_Set=Cstring_To_LPBYTE(str_username);
  DWORD type_1=REG_SZ;
  DWORD cbData_1=str_username.GetLength( )+1;
  LONG return1=::RegSetalueEx(hKey,”
DefName?,NULL,type_1,username_Set,cbData_1);
  if (return1!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法修改有关注册表信息!”);
  return;
  }
  LPBYTE company_Set=Cstring_To_LPBYTE(str_company);
  DWORD type_2=REG_SZ;
  DWORD cbData_2=str_COMPANY.GetLength( )+1;
  LONG
return2=::RegSetalueEx(hKey,”DefCompany”,NULL,type_2,company_Set,cbData_2);
  if (return2!=ERROR_SUCCESS)
  {
  MessageBox(“错误:无法修改有关注册表信息!”);
  return;
  }