废话不多说,直接上代码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);
    }
}

解决方案 »

  1.   

    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;
    }
    内容参考字网上的代码片段.稍作修改.
      

  2.   

    上次未测试写入.想当然认为读和写是两相反的过程.结果代码里并不一样.
    读上次解释过了.写入的时候,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字节.语言凌乱...见笑了
      

  3.   

    使用这个dll替换原有的dll.中文就不用转了.直接使用就可以类似registryKey.createSubKey("成功");
      

  4.   

    能做到这步很不错了,测试了下,发现用 new String(registryKey.getByteData()) 取出来的数据还是乱码
    ,不求代码,还请高手能说说这是怎么回事儿?
      

  5.   

    我不是高手.共同学习.能多贴一点代码么?new String(registryKey.getByteData()) 中的registryKey是怎么来的.
      

  6.   


    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())));
    // }
    }
    }
    }
    谢高手了,代码贴这儿~
      

  7.   


    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则这个方法也会乱码.
      

  8.   

    仔细观察了一下,这东西还真是只能从DLL方面用C去下手。在java方面做,读是没问题的,可以解决。LZ提供的RegistryUtil中decode方法也是正确做法之一。写DLL的时候,就没办法了,ice类库直接将UTF-8编码传出去了,无法从Java侧矫正。唉。
      

  9.   

    - -
    还是乱码的,我的file.encoding是 gbk的
    不过还是很感谢你,就属你最热心肠了~