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

标签 java visual-c++ unicode java-native-interface

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

目前DLL不支持Unicode,所以字符串处理比较简单:

  • Java 调用 String.getBytes() 并将生成的数组传递给 DLL,DLL 将数据简单地视为 char*。
  • DLL 使用 NewStringUTF() 从 const char* 创建 jstring。

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

我现在唯一能想到的是:

  • Java 调用 String.getBytes(String charsetName) 并将生成的数组传递给 DLL,DLL 将数据视为 wchar_t*。
  • DLL 不再创建字符串,而是将原始字符串数据传递给 jbyteArrays。 Java 使用 String(byte[] bytes, String charsetName) 构造函数来实际创建 String。

此方法的唯一问题是我不确定要使用什么字符集名称。 WCHAR 的长度为 2 个字节,所以我很确定它是 UTF-16,但在 Java 端有 3 种可能性。 UTF-16、UTF-16BE 和 UTF-16LE。我还没有找到任何文档来告诉我字节顺序是什么,但我可能可以通过一些快速测试来弄清楚。

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

最佳答案

This answer建议不能保证 WCHARS 的字节顺序......

因为你在 Windows 上,你可以尝试 <a href="http://msdn.microsoft.com/en-us/library/aa450989.aspx" rel="noreferrer noopener nofollow">WideCharToMultiByte</a>将 WCHAR 转换为 UTF-8,然后使用您现有的 JNI 代码。

您需要小心使用 WideCharToMultiByte由于缓冲区溢出的可能性 lpMultiByteStr范围。要解决这个问题,您应该调用该函数两次,首先是 lpMultiByteStr设置为 NULLcbMultiByte设置为零 - 这将返回所需 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
}

关于java - 通过 JNI 将双字节 (WCHAR) 字符串从 C++ 传递到 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/870414/

相关文章:

c++ - FFMPEG:sws_scale 返回错误:切片参数 0、2160 无效

c++ - 对重载函数错误的奇怪模棱两可的调用

python - 如何在文件中写入俄文字符?

java - 访问 Birt Cell

Java 服务器不从外部机器获取包

java - 如何通过单独的 Java 进程访问 Windows GUI 文件菜单?

.net - SHCreateStreamOnFileEx 链接器错误

Java System.out.print Windows 和 unicode 问题

regex - 使用通用 Unicode 属性

java - java写文件时出现空指针异常