我有一个C函数mpv_set_option_string
的JNA Java接口,定义为:
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
(正是我手动执行的操作),但是我得到不同的结果。
有人能对此有所启发吗?
答案 0 :(得分:1)
虽然我不确定100%发生了什么,但看起来还是找到了问题。
似乎使用W32APIOptions.DEFAULT_OPTIONS
意味着它将使用UNICODE设置(因为w32.ascii
属性为false
)。这对我来说还不错,因为mpv-1.dll
仅适用于Unicode的UTF-8字符串。
但是,现在我猜到了,在这种情况下,这意味着它将调用库函数的宽字符版本(如果不存在,则仍调用原始函数) ,这可能意味着它以每个字符两个字节的形式编码字符串。这是因为大多数Win32库具有接受字符串的ASCII和WIDE版本的方法,而对于UTF-8则没有。
由于mpv-1.dll
仅接受UTF-8(实际上不是Win32),因此字符串应仅以UTF-8格式编码为字节(基本上,不理会它们)。为了让JNA知道这一点,要么根本不传递W32APIOptions
映射,要么手动选择ASCII_OPTIONS
。
答案 1 :(得分:1)
您不应将W32OPTIONS传递给非WIN32 API的库。
默认情况下,JNA将String
映射到char*
,因此删除选项应该可以为您解决问题。
对于句柄,还应该使用显式本机类型,而不要使用Java long
。在这种情况下,Pointer
可能是正确的。