Feeling

    三人行,必有我师焉

   ::  :: 新随笔 :: 联系 ::  :: 管理 ::
  185 随笔 :: 0 文章 :: 392 评论 :: 0 Trackbacks
网上有一篇关于JNI中文问题的文章,写得很详细,http://www.vckbase.com/document/viewdoc/?id=1611

我在这里主要是想说说我碰到的一些问题,并且希望能从各位老大身上获得答案。

因为一直从事Java编程,基本上没有涉及过C++的开发,最近因为开源项目SWT Extension,不得已需要用JNI来实现一些系统Native功能。但是总是需要一些Java字符串对应C++的字符串的问题。一边情况下我都是使用SWT的TCHAR来解决问题,少部分情况需要传递Java String到JNI。然而少部分的这些Case总是在某些问题下出现乱码或者异常。我一直使用的是网上比较流行的中文编码解决方案:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
int length = env->GetStringLength(jstr );
  
const jchar* jcstr = env->GetStringChars(jstr, 0 );
  
char* rtn = (char*)malloc( length*2+1 );
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
  
if( size <= 0 )return NULL;
  env
->ReleaseStringChars(jstr, jcstr );
  rtn[size] 
= 0;
  
return rtn;
}

jstring nativeTojstring( JNIEnv
* env, char* str )
{
  jstring rtn 
= 0;
  
int slen = strlen(str);
  unsigned 
short * buffer = 0;
  
if( slen == 0 )
    rtn 
= env->NewStringUTF( str ); 
  
else
  {
    
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
    buffer 
= (unsigned short *)malloc( length*2 + 1 );
    
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
      rtn 
= env->NewString(  (jchar*)buffer, length );
  }
  
if( buffer )
  free( buffer );
  
return rtn;
}

一般情况下,这两个函数能够很好的工作。但是在读写注册表时,如果一个key的名字或者value的名字中包含了中文,jstringToNative的解决方案是不正确的,我在网上查了一下其它的关于Java访问注册表的开源项目,发现虽然它们都对字符串进行了处理,但依然存在着中文问题。我进行了数次尝试,但都没有成功。最后到了已经绝望的时候,用开头我提到的那篇文章中里说的最不可能用到的方法将问题成功地解决了:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
const char* pstr = env->GetStringUTFChars(jstr, false);
  
int nLen = MultiByteToWideChar( CP_UTF8, 0, pstr, -1, NULL, NULL );
  LPWSTR lpwsz 
= new WCHAR[nLen];    
  MultiByteToWideChar( CP_UTF8, 
0, pstr, -1, lpwsz, nLen );
  
int nLen1 = WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, NULL, NULL, NULL, NULL );    
  LPSTR lpsz 
= new CHAR[nLen1];
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, lpsz, nLen1, NULL, NULL );
  
if( size <= 0 ){
      delete [] lpwsz;
      
return NULL;
  }
  env
->ReleaseStringUTFChars(jstr, pstr );
  delete [] lpwsz;
  
return lpsz;
}
问题虽然解决了,但是我却不求甚解,为什么直接通过env拿到unicode字串,然后转成多字节串不行,但是通过env拿到utf-8字串,然后转成unicode字串,再将这个unicode字串转成多字节串就能工作?

如果大家有兴趣的话,不妨试试,用JNI调用RegOpenKeyEx这个API,就能验证我说的这个Case。哪位老大对JNI比较在行的话,可以在评论中告诉我,不甚感激。
posted on 2008-05-04 13:17 三人行,必有我师焉 阅读(4022) 评论(2)  编辑  收藏

评论

# re: JNI的中文问题 2008-05-04 15:41 Unmi
看到了,还是需要用
MultiByteToWideChar
WideCharToMultiByte

这两个宽窄字符转换的的 API 函数。  回复  更多评论
  

# re: JNI的中文问题 2008-05-04 17:40 笨笨
考虑到跨平台兼容问题,可以考虑用ICU库.
更加简单的办法:
先用String.getBytes()方法将String转为byte数组给C代码. 返回时用 new String(byte[]) 将字节数组转为String对象.
  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
 
GitHub |  开源中国社区 |  maven仓库 |  文件格式转换