網(wǎng)上有一篇關(guān)于JNI中文問題的文章,寫得很詳細(xì),
http://www.vckbase.com/document/viewdoc/?id=1611
我在這里主要是想說說我碰到的一些問題,并且希望能從各位老大身上獲得答案。
因?yàn)橐恢睆氖翵ava編程,基本上沒有涉及過C++的開發(fā),最近因?yàn)殚_源項(xiàng)目SWT Extension,不得已需要用JNI來實(shí)現(xiàn)一些系統(tǒng)Native功能。但是總是需要一些Java字符串對應(yīng)C++的字符串的問題。一邊情況下我都是使用SWT的TCHAR來解決問題,少部分情況需要傳遞Java String到JNI。然而少部分的這些Case總是在某些問題下出現(xiàn)亂碼或者異常。我一直使用的是網(wǎng)上比較流行的中文編碼解決方案:
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;
}
一般情況下,這兩個(gè)函數(shù)能夠很好的工作。但是在讀寫注冊表時(shí),如果一個(gè)key的名字或者value的名字中包含了中文,jstringToNative的解決方案是不正確的,我在網(wǎng)上查了一下其它的關(guān)于Java訪問注冊表的開源項(xiàng)目,發(fā)現(xiàn)雖然它們都對字符串進(jìn)行了處理,但依然存在著中文問題。我進(jìn)行了數(shù)次嘗試,但都沒有成功。最后到了已經(jīng)絕望的時(shí)候,用開頭我提到的那篇文章中里說的最不可能用到的方法將問題成功地解決了:
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字串,然后轉(zhuǎn)成多字節(jié)串不行,但是通過env拿到utf-8字串,然后轉(zhuǎn)成unicode字串,再將這個(gè)unicode字串轉(zhuǎn)成多字節(jié)串就能工作?
如果大家有興趣的話,不妨試試,用JNI調(diào)用RegOpenKeyEx這個(gè)API,就能驗(yàn)證我說的這個(gè)Case。哪位老大對JNI比較在行的話,可以在評論中告訴我,不甚感激。