Ответ Маттиаса Бласинга - гораздо лучшее решение для этого конкретного c варианта использования. Пожалуйста, сначала прочтите его, если вам нужна только кодировка символов.
Мой исходный ответ приведен ниже и является более общим для более широкого круга приложений.
Простой способ справиться с этим - не отображать напрямую String
полей / аргументов вообще. Просто отправьте и получите байтовые массивы из библиотеки и создайте вспомогательную функцию для преобразования между строками и байтовыми массивами. Как вы отметили, вы можете записать эти байты в выделенный блок Memory
и передать указатель.
Если вам нужно более постоянное решение, делающее то же самое за кулисами, вы можете использовать TypeMapper для этой конкретной библиотеки.
W32APITypeMapper - хороший справочник, с переменной stringConverter
, показывающей, как в юникоде она отображает String
на широкую строку WString
(UTF16 ).
Создайте свой собственный UTF8TypeMapper
(или аналогичный) и используйте функции набора символов / кодирования Java для преобразования ваших строк в последовательность байтов UTF-8.
Это не проверено, но должно быть близко к тому, что вам нужно. Вы можете сделать немного больше абстракции, чтобы создать новый тип UTF8String
, который обрабатывает детали.
public class UTF8TypeMapper extends DefaultTypeMapper {
public UTF8TypeMapper() {
TypeConverter stringConverter = new TypeConverter() {
@Override
public Object toNative(Object value, ToNativeContext context) {
if (value == null)
return null;
String str = (String) value;
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
// Allocate an extra byte for null terminator
Memory m = new Memory(bytes.length + 1);
// write the string's bytes
m.write(0, bytes, 0, bytes.length);
// write the terminating null
m.setByte((long) bytes.length, (byte) 0);
return m;
}
@Override
public Object fromNative(Object value, FromNativeContext context) {
if (value == null)
return null;
Pointer p = (Pointer) value;
// handles the null terminator
return p.getString(0, StandardCharsets.UTF_8.name());
}
@Override
public Class<?> nativeType() {
return Pointer.class;
}
};
addTypeConverter(String.class, stringConverter);
}
}
Затем добавьте преобразователь типов в параметры при загрузке библиотеки:
private static final Map<String, ?> UTF8_OPTIONS =
Collections.singletonMap(Library.OPTION_TYPE_MAPPER, new UTF8TypeMapper());
TheUTF8Lib INSTANCE = Native.load("TheUTF8Lib", TheUTF8Lib.class, UTF8_OPTIONS);