1

我有一个 C 函数的 JNA Java 接口,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终止(正是我手动执行的操作),但我得到了不同的结果。

任何人都可以对此有所了解吗?

4

2 回答 2

1

看起来我发现了这个问题,虽然我不是 100% 确定发生了什么。

似乎 usingW32APIOptions.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手动选择。

于 2019-06-15T15:56:48.543 回答
1

您不应该将 W32OPTIONS 传递给不是 WIN32 API 的库。

默认情况下,JNA 映射Stringchar*,因此删除选项应该可以为您解决问题。

您还应该为您的句柄使用显式本机类型而不是 Java longPointer在这种情况下可能是正确的。

于 2019-06-19T16:43:43.223 回答