代码之家  ›  专栏  ›  技术社区  ›  Herms

通过JNI将双字节(WCHAR)字符串从C++传递到Java

  •  8
  • Herms  · 技术社区  · 17 年前

    我有一个Java应用程序,它通过JNI使用C++DLL。DLL的一些方法接受字符串参数,其中一些方法也返回包含字符串的对象。

    我现在正在修改DLL以支持Unicode,切换到使用TCHAR类型(定义Unicode时使用windows的WCHAR数据类型)。修改DLL进展顺利,但我不确定如何修改代码的JNI部分。

    我现在唯一能想到的是:

    • Java调用String.getBytes(String charsetName)并将结果数组传递给DLL,DLL将数据视为wchar_t*。

    有更好的办法吗?如果可能的话,我想继续在DLL中构造jstring对象,这样我就不必修改这些方法的任何用法。但是,NewString JNI方法不接受字符集标识符。

    2 回复  |  直到 17 年前
        1
  •  7
  •   Community Mohan Dere    9 年前

    This answer 表明WCHARS的字节顺序没有保证。..

    既然你在Windows上,你可以试试 WideCharToMultiByte

    宽字符转多字节 由于缓冲区溢出的可能性 lpMultiByteStr 参数。为了绕过这个问题,你应该调用该函数两次,首先用 lpMultiByteStr 着手 NULL cbMultiByte lpMultiByteStr

    int utf8_length;
    
    wchar_t* utf16 = ...;
    
    utf8_length = WideCharToMultiByte(
      CP_UTF8,           // Convert to UTF-8
      0,                 // No special character conversions required 
                         // (UTF-16 and UTF-8 support the same characters)
      utf16,             // UTF-16 string to convert
      -1,                // utf16 is NULL terminated (if not, use length)
      NULL,              // Determining correct output buffer size
      0,                 // Determining correct output buffer size
      NULL,              // Must be NULL for CP_UTF8
      NULL);             // Must be NULL for CP_UTF8
    
    if (utf8_length == 0) {
      // Error - call GetLastError for details
    }
    
    char* utf8 = ...; // Allocate space for UTF-8 string
    
    utf8_length = WideCharToMultiByte(
      CP_UTF8,           // Convert to UTF-8
      0,                 // No special character conversions required 
                         // (UTF-16 and UTF-8 support the same characters)
      utf16,             // UTF-16 string to convert
      -1,                // utf16 is NULL terminated (if not, use length)
      utf8,              // UTF-8 output buffer
      utf8_length,       // UTF-8 output buffer size
      NULL,              // Must be NULL for CP_UTF8
      NULL);             // Must be NULL for CP_UTF8
    
    if (utf8_length == 0) {
      // Error - call GetLastError for details
    }
    
        2
  •  2
  •   Onots    17 年前

    a little faq 同样来自FAQ:

    UTF-16和UTF-32分别使用2字节和4字节长的代码单元。对于这些UTF,有三个子风格:BE、LE和无标记。默认情况下,BE形式使用大端字节序列化(最高有效字节优先),LE形式使用小端字节序列化,无标记形式使用大端字节序列化,但可能在开头包含字节顺序标记,以指示实际使用的字节序列化。

    我假设在java端,UTF-16将尝试找到此BOM并正确处理编码。我们都知道假设有多危险。。。

    因评论而编辑:

    微软使用UTF16小字节序。Java UTF-16试图解释BOM。当缺少BOM时,它默认为UTF-16BE。BE和LE变体忽略BOM。

    推荐文章