跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

远程注册表访问

一种实用实现

Nigel Morton 是在英国 Hursley Park 工作的软件工程师。自从 2000 年 9 月以来,他一直为 IBM 的商业集成(Business Integration)项目工作。在加入 IBM 以前,他开发过银行业和电信业的集成解决方案和消息传递软件。可通过 nmorton1@uk.ibm.com与 Nigel Morton 联系。

简介: 本文是 Brian Venn 的文章 利用远程注册表访问(developerWorks,2002 年 1 月)的后续。本文不需要 InstallShield 就可以启用注册表查询(正如 Brian Venn 原先所描述的那样),这看起来是个不错的想法。用于注册表操作的所有函数都包含在 Windows API 中,所以这看起来是个试用部分 Windows API 的理想机会。

发布日期: 2002 年 8 月 01 日
级别: 初级
访问情况 : 1177 次浏览
评论: 


必要的函数

要启用远程注册表操作,必需实现两个函数:对远程注册表读出和写入的能力。

读和写函数已经被封装进了 RegConnect DLL。该 DLL 本身隐藏了这些函数实际操作原理的复杂性,稍后我们将对此进行描述。DLL 执行实际连接/断开和读/写函数,并提供了两个易于使用的函数。

可以通过任何能够利用 DLL 的语言(如 C 或 Visual Basic)调用这些函数。要允许从 Java 环境使用 DLL,得做一些额外的工作。

清单 123说明了这些函数的原型。


清单 1. C/C++ 原型函数
int WINAPI RegDBGetKeyValueEx(LPCTSTR MachineName, HKEY RegKey, LPCTSTR KeyName,
LPCTSTR ValueName, LPTSTR KeyValue) ;

int WINAPI RegDBSetKeyValueEx(LPCTSTR MachineName, HKEY RegKey, LPCTSTR KeyName,
LPCTSTR ValueName, LPTSTR KeyValue) ;



清单 2. Visual Basic 原型函数
Declare Function RegDBGetKeyValueEx Lib "RegConnect.dll" (ByVal MachineName As String,
ByVal RegKey As Long, ByVal KeyName As String, ByVal ValueName As String,
ByVal KeyValue As String)
As Integer

Declare Function RegDBSetKeyValueEx Lib "RegConnect.dll" (ByVal MachineName As String,
ByVal RegKey As Long, ByVal KeyName As String, ByVal ValueName As String,
ByVal KeyValue As String)
As Integer



清单 3. Java 原型函数
public native String RegDBGetKeyValueEx(String MachineName, int RegKey,
String KeyName, String ValueName) ;

注:因为函数将字符串作为调用结果返回,所以对于 Java 没有 KeyValue 参数。

public native int RegDBSetKeyValueEx(String MachineName, int RegKey, String KeyName,
String ValueName, String KeyValue) ;

公用类 GetKey 和 SetKey 定义了调用和变量。这些类可以用来调用 DLL 函数。

函数参数

对于所有语言,参数如下:

  • MachineName:您希望询问的机器的名称 ― 如果这是一个空字符串,则询问本地机器
  • RegKey:您希望查询的根键值,即 HKEY_LOCAL_MACHINE
  • KeyName:您希望查询的键名称,即 SOFTWARE\IBM\DB2
  • ValueName:您希望查询的键中值的名称,即 DB2 Folder Name

对于获取键(除了 Java 函数以外):

  • KeyValue:在该参数中将返回键值

对于设置键:

  • KeyValue:您希望设置的键值

使用函数

通过用所需参数调用各个函数来实现对这些函数的调用。当调用 RegDBGetKeyValueEx 时,某些语言需要用于返回字符串的预定义存储器。如果没有预先分配这个存储器,那么,该函数可能会(并且很可能会)失败。

正如其实现的那样,RegDBGetKeyValueEx 函数仅限于返回注册表字符串(REG_SZ)和数字(DWORD)数据。还请注意,RegDBGetKeyValueEx 仅返回字符串 ― DWORD 值是作为与其等价的 ASCII 数值返回的。

当使用 RegDBSetKeyValueEx 函数来创建键时,如果该键不存在,则将创建键名和键值,记住这一点很重要。如果键已经存在,则原先的值将被覆盖。还请注意,正如其实现的那样,RegDBSetKeyValueEx 将仅存储字符串值。

清单 4显示了一个用 Visual Basic 函数封装 RegDBGetKeyValueEx 函数的示例。


清单 4. Visual Basic 示例
Function GetRegValue(szMachine$, hKey&, szRegTree$, szKey$) As String
Dim Temp&, sReturn$

   sReturn$ = Space(128)           'Pre-define storage for the returned value
   Temp& = RegDBGetKeyValueEx(szMachine$, hKey&, szRegTree$,
   szKey$, sReturn$)
   GetRegValue = Left$(sReturn$, InStr(sReturn$, Chr$(0)))

End Function

为了在 Java 环境中使用这些函数,使用类 GetKey 和 SetKey。 清单 5中的下列示例演示了使用 Java 设置和检索键。


清单 5. Java 示例
// Test for registry read/write using JNI call to RegConnect.dll

class RegTest
{
   public static void main(String[] args)
   {
   // Set a registry key value
   SetKey skey = new SetKey() ;

   skey.RegKey = skey.HKEY_LOCAL_MACHINE ;
   skey.MachineName = "" ;
   		//Change this to a remote machine if you wish
   skey.KeyName = "software\\IBM\\MyKey" ;
   skey.ValueName ="test" ;
   skey.KeyValue ="My NEW reg value" ;
   skey.iResult = skey.RegDBSetKeyValueEx(skey.MachineName, skey.RegKey,
   		skey.KeyName,
   skey.ValueName, skey.KeyValue) ;
   System.out.println("Set Result is " + skey.iResult); //Display the result of the call

   // Now read the value back again
   GetKey gkey = new GetKey() ;

   gkey.RegKey = gkey.HKEY_LOCAL_MACHINE ;
   gkey.MachineName = "" ;
   		//Change this to a remote machine if you wish
   gkey.KeyName = "software\\IBM\\MyKey" ;
   gkey.ValueName ="test" ;
   gkey.KeyValue = gkey.RegDBGetKeyValueEx(gkey.MachineName, gkey.RegKey,
   		gkey.KeyName, gkey.ValueName) ;
   System.out.println("Data is " + gkey.KeyValue);      //Display the key value
   }
}


DLL 代码(完成所有工作的那部分)

本文所提供的实现 Registry 功能的 DLL 使用标准 Windows API 调用来执行其函数。两个函数的初始需求都是连接到远程注册表。使用下列函数调用实现这一点:

// Connect to the remote registry
lRC = RegConnectRegistry(cMachine, hRegKey, &hRemoteKey) ;

这个函数调用的重要参数是正在连接的远程机器名和您希望访问的注册表的根。这些参数包含于用于机器名的 cMachine 参数和用于注册表根的 hRegKey 参数中。hRegKey 参数实际上只是一个长数据类型,它是用与所需注册表根相关的值设置的。这些值被声明为常数值,即 HKEY_CURRENT_USER。剩下的那个参数返回一个指向该注册表的句柄,其余函数使用该句柄来访问该远程注册表。

一旦获得了到远程机器的注册表的连接,就可以执行对该注册表读或写的函数。

如果正在调用设置键值的函数,则要设置的注册表项可能不存在。为了确保该项存在,调用 RegCreateKeyEx 函数。这样做的效果是创建该项(如果它不存在)或仅打开该项以便访问(如果它已经存在)。返回的 hKey 值是一个句柄,它指向下列函数调用中使用的注册表键。下列代码显示了执行这个操作的函数调用:

//  Initialize variables
lRC = RegCreateKeyEx(hRemoteKey, lpKeyName, 0, REG_NONE,
      REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp) ;

当读取键时,只需要获得指向注册表键的句柄。使用 API 调用 RegOpenKeyEx 来获取必要的 hKey 注册表句柄,如下所示。

lRC = RegOpenKeyEx(hRemoteKey, lpKeyName, 0, KEY_ALL_ACCESS, &hKey);

注册表项可以是多种类型,包括字符串和数字。当读入项时,了解正在读取的项的类型很重要。这可以通过调用 RegQueryValueEx 获取的注册表键数据类型进行确定。dwKeyDataType 参数返回键的数据类型。下面显示了该函数。

// Got key, get value.  First, get the size of the key.
lRC = RegQueryValueEx(hKey, lpValueName, NULL, &dwKeyDataType, NULL, &dwKeySize);

我们可以使用 dwKeyDataType 值确定得到的是字符串值还是数字值,并查询该键以便正确返回该值,如下所示。

if(dwKeyDataType == REG_DWORD) //DWORD (Numeric value)
{
  char cData[128] = {0} ;
  lRC = RegQueryValueEx(hKey, lpValueName, NULL, &dwKeyDataType, (LPBYTE)cData
     &dwKeySize);
  ltoa((LONG)cData[0], lpszKeyValue, 10) ;
}
else
  // Now get the actual key value
  lRC = RegQueryValueEx(hKey, lpValueName, NULL, &dwKeyDataType, 
     (LPBYTE)lpszKeyValue, &dwKeySize);

为了使 DLL 函数保持简单,RegDBGetKeyValueEx 函数只返回字符串值。因为注册表可以包含数值,所以所有返回的数值都被转换成字符串。使用调用应用程序自身的函数,很容易将该字符串转换回数字值。如上所示,ltoa 函数是用来将数值转换成字符串的。在任一函数的结束部分都必须关闭注册表。这是通过调用 RegCloseKey API 函数完成的。


DLL 的 Java 支持

Java 能够通过使用 JNI 接口调用 DLL 中的函数。要允许与 Java 一起使用 DLL,需要在类文件中设置用于 DLL 的 Java 可调用函数。首要任务是为每个函数创建一个 Java 类。用于 GetKey 函数的类如下:

// Class to read a registry key from a local or remote machine
public class GetKey{
       int RegKey ;                  //Key value, that is, HKEY_CLASSES_ROOT
       String MachineName ;          //Machine name we want to interrogate
       String KeyName ;              //Name of key we want to read
       String ValueName ;            //Value of key we want to read
       String KeyValue ;             //Return value from key

       public native String RegDBGetKeyValueEx(String MachineName, int RegKey,
          String KeyName, String ValueName) ;
       public static final int HKEY_CLASSES_ROOT = 0x80000000 ;
       public static final int HKEY_CURRENT_USER = 0x80000001 ;
       public static final int HKEY_LOCAL_MACHINE = 0x80000002 ;
       public static final int HKEY_USERS = 0x80000003 ;
       public static final int HKEY_CURRENT_CONFIG = 0x80000005 ;
       public static final int HKEY_DYN_DATA = 0x80000006 ;

       static
       {
         System.loadLibrary("RegConnect") ;
       }
}

如代码所示,值和函数都与 C 或 Visual Basic 所使用的值和函数非常相似。

一旦创建了类,就可以使用 JDK 函数 Javah 来为 DLL 创建一个能包含在 C 代码中的头文件。该头文件包含类函数的所有 C 实现代码。这和打开一个命令提示符、更改到驻留 Java 源文件的目录以及运行命令 javah GetKey 一样简单。这个操作将创建可以被包含到 C 代码中的 GetKey.h 文件。相同过程也适用于创建 SetKey.h 头文件。

最后,需要在 JNI 代码中封装 C 函数。从 Javah JDK 实用程序创建的头文件中复制函数原型:

// Java implementation of RegDBGetKeyValueEx
JNIEXPORT jobject JNICALL Java_GetKey_RegDBGetKeyValueEx(JNIEnv* env, jobject this_obj,
  jstring jMachineName, jint hRegKey, jstring jKeyName, jstring jValueName)

接下来,为调用 C 函数所需的每个字符串创建参数:

LPCTSTR lpMachineName ;
LPCTSTR lpKeyName ;
LPCTSTR lpValueName ;
char cKeyValue[255] ;

最后,为函数返回声明 Java 对象:

jobject ret ;

当进行 JNI 调用时,Java 向该函数传递一个对象。这个对象必需是非绑定的,并且获取了字符串。JNI 函数 GetStringUTFChars 执行这个任务。用下列代码用来获取字符串:

lpMachineName = (*env)->GetStringUTFChars(env, jMachineName, NULL) ;
lpKeyName = (*env)->GetStringUTFChars(env, jKeyName, NULL) ;
lpValueName = (*env)->GetStringUTFChars(env, jValueName, NULL) ;

现在,我们已准备好调用 C 函数了。下面显示了该调用,它带有从 Java 对象获取的参数:

RegDBGetKeyValueEx(lpMachineName, (HKEY)hRegKey, lpKeyName, lpValueName, cKeyValue) ;

我们现在已经完成了 Java 对象的使用,所以需要释放它们使用的字符串和内存。ReleaseStringUTFChars 函数执行这个任务,如下所示:

(*env)->ReleaseStringUTFChars(env, jMachineName, NULL) ;
(*env)->ReleaseStringUTFChars(env, jKeyName, NULL) ;
(*env)->ReleaseStringUTFChars(env, jValueName, NULL) ;

最后,我们需要将从注册表获取的字符串存放到正在返回的 Java 对象,然后将该对象返回到 Java 程序。JNI 函数 NewStringUTF 执行该任务,如下所示:

ret = (*env)->NewStringUTF(env, cKeyValue) ;
return ret ;

这就是所有步骤。如果您检查所提供的代码,就会发现 SetKey 函数几乎和 GetKey 函数相同。


示例代码

本文提供的代码(请参阅 参考资料)包含下列内容:

  • RegConnect.DLL 源代码,Visual Studio 6 工程以及预构建的发行版 DLL
  • Java 类和头文件以及用来试验函数的 Java 样本
  • 封装了函数调用并演示函数的 Visual Basic 工程

结束语

本文说明了如何通过使用 DLL 执行 Windows API 函数调用来实现本地或远程注册表操作。它提供了从 Java 和 Visual Basic 环境使用 DLL 的样本。注册表操作可以成为任何程序的有用补充,因为它允许保存和检索运行时配置数据。


参考资料

关于作者

Nigel Morton 是在英国 Hursley Park 工作的软件工程师。自从 2000 年 9 月以来,他一直为 IBM 的商业集成(Business Integration)项目工作。在加入 IBM 以前,他开发过银行业和电信业的集成解决方案和消息传递软件。可通过 nmorton1@uk.ibm.com与 Nigel Morton 联系。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=21688
ArticleTitle=远程注册表访问
publish-date=08012002
author1-email=nmorton1@uk.ibm.com
author1-email-cc=nmorton1@uk.ibm.com

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。