網上有一篇關于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比較在行的話,可以在評論中告訴我,不甚感激。