关于用registry.jar操作windows注册表的问题,大家来看看啊

君宝儿 2011-04-15 10:34:36
废话不多说,直接上代码

public class CopyOfRegistryManager2 {
public static void main(String[] args) throws NoSuchKeyException,
RegistryException {
RegistryKey registryKey = Registry.openSubkey(
Registry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
RegistryKey.ACCESS_READ);

registryKey.createSubKey(RegistryUtil.decode("成功"), "");
}
}

跑到注册表里面一看,还是乱码 -- 锟
如果哪位大侠百忙之中能够抽出一点空来的话,不妨帮我改下代码,我的需求很简单,从注册表中取出所有
安装程序的信息,
也就是遍历 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
的所有子键,取出每个子键的 DisplayName 属性打印出来(子键名有中文,子键的DisplayName属性也包含中文)
我把代码粘上吧

package available.registry.test;

import java.util.Enumeration;

import available.registry.basic.RegistryUtil;

import com.ice.jni.registry.NoSuchKeyException;
import com.ice.jni.registry.Registry;
import com.ice.jni.registry.RegistryException;
import com.ice.jni.registry.RegistryKey;
import com.ice.jni.registry.RegistryValue;

// 这个类使用了 registry.jar 中 jni 提供的功能!
public class RegistryManager {
private final Object o = new Object();
public static void main(String[] args) throws NoSuchKeyException,
RegistryException {
// 提示如何在命令行下使用 registry.jar 文件,参数到底是什么意思?
// Registry.usage("123");

// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
RegistryKey rootRK = Registry.openSubkey(
Registry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\",
RegistryKey.ACCESS_READ);
RegistryManager rm = new RegistryManager();

Enumeration<?> enums = rootRK.keyElements();
while (enums.hasMoreElements()) {
synchronized(rm.o) {
String childRKName = (String)enums.nextElement();
String childRKNameDecoded = RegistryUtil.decode(childRKName);
System.err.println("之后 " + childRKNameDecoded);

rm.getDisplayAttr(rootRK, childRKNameDecoded);
}
}
}

// “根键” 和 “枚举出来的子键名”
public synchronized void getDisplayAttr(RegistryKey rootRK, String childRKNameDecoded) throws NoSuchKeyException,
RegistryException {
RegistryKey childRK = null;
try {
childRK = rootRK.openSubKey(RegistryUtil.encode(childRKNameDecoded), RegistryKey.ACCESS_READ);
} catch (com.ice.jni.registry.NoSuchKeyException e) {
System.out.println(childRKNameDecoded + " 找不到这个键!");
}

if(childRK != null) {
// 获取子键的 DisplayName 属性的值
String subKeyName = RegistryUtil.decode(childRK.getName());

System.out.println("子键的名字为:" + subKeyName);
RegistryValue rv = null;
try {
rv = childRK.getValue("DisplayName");
} catch (com.ice.jni.registry.NoSuchValueException e) {
System.err.println("该子键没有这个 DisplayName 这个属性~");
}
if (rv != null) {
System.out.print(childRK.getName()+" 子键 DisplayName 属性的值为:");
String name = RegistryUtil.decode(new String(rv.getByteData()));
if(name == null) {
System.err.println("null");
} else if(name.equals("")) {
System.err.println("equals(\"\")");
} else {
System.err.println(name);
}
System.out.println();
}
}
}
}


package available.registry.basic;

import java.io.UnsupportedEncodingException;

public class RegistryUtil {
/**
* 将dll获取的字符串拼接回原来的形式.
* 因为dll内以前的方法只是单纯的将byte复制到java的char里
* if ( uniBuf != NULL )
{
for ( i = 0 ; i < len ; ++i )
uniBuf[i] = (jchar) buf[i];
result = (*env)->NewString( env, uniBuf, (jsize)len );
free( uniBuf );
}
return result;

* @param str 从dll获取的字符串
* @return
* @throws UnsupportedEncodingException
*/
public static String decode(String str) {
String result = null;
char[] charbuf = str.toCharArray();
byte[] bytebuf = new byte[charbuf.length];
for(int i=0;i<charbuf.length;i++){
bytebuf[i] = (byte)charbuf[i];
}
try {
result = new String(bytebuf,"GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}

/**
* 相反要传入中文的字符来操作,需要修改中文为他所识别的乱码...即将中文按两字节一个,拆分开
* @param str
* @return
*/
public static String encode(String str) {
byte[] bytebuf = null;
try {
bytebuf = str.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
char[] charbuf = new char[bytebuf.length];
for(int i=0;i<bytebuf.length;i++){
charbuf[i] = (char)bytebuf[i];
}
return new String(charbuf,0,charbuf.length);
}
}



...全文
284 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
十分感谢2楼和楼主。
xjmlj2010 2011-04-16
  • 打赏
  • 举报
回复
很不错呀
君宝儿 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 qingralf 的回复:]

Java code

String s = new String(rv.getByteData(), "utf-8");
byte[] tmp = new byte[s.length()];
for(int i=0;i<s.length();i++){
tmp[i] = (byte)s.to……
[/Quote]
- -
还是乱码的,我的file.encoding是 gbk的
不过还是很感谢你,就属你最热心肠了~
君宝儿 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 qingralf 的回复:]

使用这个dll替换原有的dll.中文就不用转了.直接使用就可以

类似registryKey.createSubKey("成功");
[/Quote]
能做到这步很不错了,测试了下,发现用 new String(registryKey.getByteData()) 取出来的数据还是乱码
,不求代码,还请高手能说说这是怎么回事儿?
magong 2011-04-16
  • 打赏
  • 举报
回复
仔细观察了一下,这东西还真是只能从DLL方面用C去下手。

在java方面做,读是没问题的,可以解决。LZ提供的RegistryUtil中decode方法也是正确做法之一。

写DLL的时候,就没办法了,ice类库直接将UTF-8编码传出去了,无法从Java侧矫正。唉。
君宝儿 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 qingralf 的回复:]

使用这个dll替换原有的dll.中文就不用转了.直接使用就可以

类似registryKey.createSubKey("成功");
[/Quote]
无论如何,还是很感谢您~
qingralf 2011-04-16
  • 打赏
  • 举报
回复

String s = new String(rv.getByteData(), "utf-8");
byte[] tmp = new byte[s.length()];
for(int i=0;i<s.length();i++){
tmp[i] = (byte)s.toCharArray()[i];
}
s = new String(tmp,"gbk");//这个是正常结果


原因构造RegStringValue等RegistryValue类型的时候,是先用无参的构造方法初始化,然后再setData的.
而setData方法中的data是在dll中getStringValueData方法取得.该方法直接把取得的值按gbk编码拆分,每个字节强转为jchar.
for ( i = 0 ; i < dwBufSize ; ++i )
uniBuf[i] = (jchar) strData[i];

RegistryValue 的getByteData方法中直接return this.data.getBytes();是按默认的字符集取得byte数组.默认字符集一般为file.encoding或者UTF-8.这里按utf8取.如果该java文件的编码类型不是utf8则这个方法也会乱码.
君宝儿 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 qingralf 的回复:]

引用 7 楼 lovedpyj 的回复:
引用 5 楼 qingralf 的回复:

使用这个dll替换原有的dll.中文就不用转了.直接使用就可以

类似registryKey.createSubKey("成功");

能做到这步很不错了,测试了下,发现用 new String(registryKey.getByteData()) 取出来的数据还是乱码
,不求代码,还请高手能说……
[/Quote]

package available.registry.test;

import java.io.UnsupportedEncodingException;
import java.util.Enumeration;

import available.registry.basic.RegistryUtil;

import com.ice.jni.registry.NoSuchKeyException;
import com.ice.jni.registry.NoSuchValueException;
import com.ice.jni.registry.Registry;
import com.ice.jni.registry.RegistryException;
import com.ice.jni.registry.RegistryKey;
import com.ice.jni.registry.RegistryValue;

public class CatchException {
public static void main(String[] args) throws NoSuchKeyException,
RegistryException {
RegistryKey registryKey = Registry.openSubkey(
Registry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
RegistryKey.ACCESS_READ);

Enumeration<?> enums = registryKey.keyElements();

// 360保险箱 0xB1A3 0xCFD5 0xCFE4
while(enums.hasMoreElements()) {
String childRKName = (String)enums.nextElement();

// if(childRKName.equals("360安全卫士")) {
RegistryKey rk = registryKey.openSubKey(childRKName, RegistryKey.ACCESS_READ);
RegistryValue rv = null;
try {
rv = rk.getValue("DisplayName");
} catch (NoSuchValueException e1) {
// 仅仅 catch 运行时异常的话会终止程序运行,只有具体到是哪种 Exception,才会继续执行~
e1.printStackTrace();
}

// 如果上句代码抛出异常,则这里的rv必定为null,不做处理的话必然会报空指针~
if(rv == null) continue;
String s = null;
try {
s = new String(rv.getByteData(), "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(s + " ====================== " +
RegistryUtil.decode(new String(rv.getByteData())));
// }
}
}
}


谢高手了,代码贴这儿~
qingralf 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 lovedpyj 的回复:]
引用 5 楼 qingralf 的回复:

使用这个dll替换原有的dll.中文就不用转了.直接使用就可以

类似registryKey.createSubKey("成功");

能做到这步很不错了,测试了下,发现用 new String(registryKey.getByteData()) 取出来的数据还是乱码
,不求代码,还请高手能说说这是怎么回事儿?
[/Quote]
我不是高手.共同学习.能多贴一点代码么?new String(registryKey.getByteData()) 中的registryKey是怎么来的.
qingralf 2011-04-16
  • 打赏
  • 举报
回复
使用这个dll替换原有的dll.中文就不用转了.直接使用就可以

类似registryKey.createSubKey("成功");
qingralf 2011-04-16
  • 打赏
  • 举报
回复
上次未测试写入.想当然认为读和写是两相反的过程.结果代码里并不一样.
读上次解释过了.写入的时候,java传入了个jstring类型的字符串.转化为本地字符的时候乱码.所以会找不到.
原来的转化本地字符方法如下:

char *
jStringToNewAscii( JNIEnv *env, jstring jStr )
{
int i;
int utfLen;
jboolean isCopy;
char *asciiBuf;
const char *utfBuf;

utfLen = (*env)->GetStringUTFLength( env, jStr );
utfBuf = (*env)->GetStringUTFChars( env, jStr, &isCopy );

asciiBuf = malloc( utfLen + 2 );
if ( asciiBuf != NULL )
{
for ( i = 0 ; i < utfLen ; ++i )
asciiBuf[i] = utfBuf[i];

asciiBuf[i] = '\0';

(*env)->ReleaseStringUTFChars( env, jStr, utfBuf );
}

return asciiBuf;
}

由于本地字符集一般都是gbk.所以按上述方法,直接读取字符的utf-8形式,在本地是找不到所对应的键名的.

也想着不改dll.换种方式在java内处理.后来考虑到不可行.
原方法是直接获取传入参数的utf-8字节数组并复制到一个新的数组,当一个字符串返回.可需要的字符串是gbk编码的.
以"中文"这两字为例,gbk编码是4个字节[0xD6,0xd0,0xce,0xc4],如果有一个java字符串是以utf-8格式保存,而且只占用4个字节,而且这四个字节刚好是"中文"的gbk编码.那就可以传入这个字符来取到名称为"中文"的键值.可是不存在这样的utf-8的字符串.因为根据utf-8的编码规则,以一个字节保存的字符范围为0000 0000 - 0000 007F,即D6不能以一个utf-8字节保存,可超过1个字节的话,最终结果也就超过了4字节.

语言凌乱...见笑了
qingralf 2011-04-16
  • 打赏
  • 举报
回复
http://download.csdn.net/source/3195805

修改后的registry.dll修改内容贴到下面了.简单测试了一下.读写都没什么问题.


jstring
strbufToJString( JNIEnv *env, char *buf, int len )
{
jstring encoding = (*env)->NewStringUTF(env, "gbk");
jclass strClass = (*env)->FindClass(env, "Ljava/lang/String;");
jmethodID ctorID = (*env)->GetMethodID(env, strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env, len);
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)buf);

return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);
}

char *
jStringToNewAscii( JNIEnv *env, jstring jstr )
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env, "gbk");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode);
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = '\0';
}else{
rtn = (char*)malloc(1);
rtn[0] = '\0';
}
(*env)->ReleaseByteArrayElements(env, barr, ba, 0);
return rtn;
}


内容参考字网上的代码片段.稍作修改.

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧