Вызов JNA со строкой ведет себя иначе, чем вызов с байтом [] - PullRequest
1 голос
/ 15 июня 2019

У меня есть интерфейс JNA Java для функции C mpv_set_option_string, определенный как:

public interface MPV extends StdCallLibrary {
    MPV INSTANCE = Native.loadLibrary("lib/mpv-1.dll", MPV.class, W32APIOptions.DEFAULT_OPTIONS);

    long mpv_create();
    int mpv_initialize(long handle);
    int mpv_set_option_string(long handle, String name, String data);
}

Когда я называю это так:

System.setProperty("jna.encoding", "UTF8");

long handle = MPV.INSTANCE.mpv_create();
int error = MPV.INSTANCE.mpv_initialize(handle);
error = MPV.INSTANCE.mpv_set_option_string(handle, "keep-open", "always");

При последнем вызове возвращается ошибка (-5), указывающая, что опция (keep-open) не найдена.

Однако, если я изменю сигнатуру функции JNA на:

int mpv_set_option_string(long handle, byte[] name, byte[] data);

... а затем назовите это так:

error = MPV.INSTANCE.mpv_set_option_string(
    handle, 
    "keep-open\0".getBytes(StandardCharsets.UTF_8),
    "always\0".getBytes(StandardCharsets.UTF_8)
);

... он не возвращает ошибки (0) и работает правильно (или, кажется, так).

Что я не получаю, так это то, что JNA по умолчанию должен кодировать String как char * с кодировкой UTF-8 и завершать NUL (именно то, что я делаю вручную), но я получаю разные результаты.

Кто-нибудь может пролить свет на это?

Ответы [ 2 ]

1 голос
/ 19 июня 2019

Вы не должны передавать W32OPTIONS в библиотеку, которая не является API-интерфейсом WIN32.

По умолчанию JNA сопоставляет String с char*, поэтому удаление опций должно решить проблему для вас..

Вы должны также использовать явный собственный тип для своего дескриптора вместо Java long.Pointer, вероятно, правильно в этом случае.

1 голос
/ 15 июня 2019

Похоже, я нашел проблему, хотя я не уверен на 100%, что происходит.

Кажется, что использование W32APIOptions.DEFAULT_OPTIONS означает, что оно будет использовать настройки UNICODE (потому что свойство w32.ascii равно false). Это выглядело нормально для меня, так как mpv-1.dll работает только со строками UTF-8, то есть Unicode.

Однако, теперь я предполагаю , что в этом случае это означает, что она вызовет версию библиотеки с широким символом (и, если она не существует, все равно вызовет исходную функцию), и, вероятно, означает, что он кодирует строки с двумя байтами на символ. Это потому, что большинство библиотек Win32 имеют ASCII и WIDE версию методов, принимающих строки, но ничего для UTF-8.

Поскольку mpv-1.dll принимает только UTF-8 (и на самом деле не Win32), строки должны быть просто закодированы как байты в формате UTF-8 (в основном, просто оставьте их в покое). Чтобы сообщить об этом JNA, либо вообще не проходите карту W32APIOptions, либо выберите ASCII_OPTIONS вручную.

...