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