当前位置: 首页 > 知识库问答 >
问题:

JNA:仅更改一个外部本机库的字符串编码

谭京
2023-03-14

我们这里有一个JAVA应用程序,它加载和使用许多外部库。操作系统(视窗)的默认编码是“视窗-1252”(或“cp-1252”)。但是有一个外部库想要“utf-8”中的所有字符串(传入和传出)。我该怎么做?我如何才能只为一个JNA库更改字符串编码类型?

共有3个答案

西门凯康
2023-03-14

我发现的唯一方法是使用JNA的函数类(参见https://java-native-access.github.io/jna/5.2.0/javadoc/com/sun/jna/Function.html)就像这样:

public void setIp(String ip) {
    Function fSetIp = Function.getFunction("myLib", "setIp", Function.C_CONVENTION, "utf-8");

    Object[] args = {ip};

    fSetIp.invoke(args);
}

但我必须为我想调用的每个函数实现这个。不确定是否有更好/更简单的方法。如果是,请回答我的问题。

冯哲彦
2023-03-14

Matthias Bläsing的答案是针对这个特定用例的更好的解决方案。如果你只需要字符编码,请先阅读。

下面是我最初的答案,对于更广泛的应用来说更为普遍。

处理它的一个简单方法是根本不直接映射String字段/args。只需从库中发送和接收字节数组,并创建一个助手函数来进行Strings和字节数组之间的转换。正如您已经指出的,您可以将这些字节写入分配的Memory块并传递指针。

如果你想要一个更持久的解决方案在幕后做同样的事情,你可以为这个特定的库使用一个类型映射器。

W32 PitypeMapper是一个很好的参考,它的stringConverter变量显示了它如何在unicode中将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);
党权
2023-03-14

正常的JNA模式是:

public interface DemoLibrary extends Library {

    DemoLibrary INSTANCE = Native.load("demoLibrary", DemoLibrary.class);

    // abstract method declarations as interface to native library
}

然而,本机#加载被多次重载,以支持自定义绑定。相关重载是:本机#加载(字符串、类、映射

这里的相关选项是库。选项_字符串_编码。该选项被传递给加载的NativeLibrary实例,并将用作此类的默认编码。

上面的样本变成了然后

public interface DemoLibrary extends Library {

    DemoLibrary INSTANCE = Native.load("demoLibrary", DemoLibrary.class,
        Collections.singletonMap(Library.OPTION_STRING_ENCODING, "UTF-8"));

}

如果您需要自定义更多(typemapper,调用约定),您需要创建选项映射,例如在静态初始化器块中。

 类似资料:
  • 目前,我有一个很大的JavaScript字符串,我正试图写入一个文件,但编码方式不同(ISO-8859-1)。我希望使用类似downloadify的东西。Downloadify只接受普通JavaScript字符串或base64编码字符串。 因此,我决定使用JSZip压缩我的字符串,JSZip生成一个很好的base64编码字符串,可以传递给downloadify并下载到我的桌面。胡萨!问题是,我压缩

  • 问题内容: Python中替换字符串中字符的最简单方法是什么? 例如: 问题答案: 不要修改字符串。 与他们一起工作作为清单;仅在需要时才将它们转换为字符串。 Python字符串是不可变的(即无法修改)。有很多的原因。使用列表,直到你别无选择,然后将它们变成字符串。

  • 我正在尝试制作一个打字游戏,我为用户输入创建了一个文本字段,并尝试制作游戏,以便文本字段的最后一个字符是红色的,如果它不匹配要键入的单词中的相应字符。以下是我目前所掌握的相关节点的类型。

  • 我想用Java将一个文件放入Windows中的回收站。以便用户能够还原它。

  • 我认为每次更改字符串后,Python字符串的id都必须更改。但我发现真正的行为是不同的。例如,并非输出下面的所有代码字符串都不同: 这就是为什么我认为Python内核正在尝试优化代码,并开始对内存中的字符串进行奇怪的操作。该假设的另一个论点是,常量ID与大小为2的幂的段相关联: 但这其中还有一件奇怪的事。让我们看看随着字符串大小的增加,段大小会发生什么变化: 最后,我们可以尝试近似地将char添加

  • 我正在处理一个关于codingbat的问题,这个问题说:给定一个字符串和第二个“单词”字符串,我们会说这个单词匹配字符串,如果它出现在字符串的前面,除了它的第一个字符不需要完全匹配...在匹配时,返回字符串的前面,或以其他方式返回空字符串。所以,所以用字符串“河马”,“嗨”这个词返回“嗨”,“xip”返回“臀部”。单词长度至少为1。我不能解决它,但在网上找到了一个解决方案,代码如下所示。代码工作,