【问题标题】:Passing an array from a Delphi DLL to JNA将数组从 Delphi DLL 传递到 JNA
【发布时间】:2014-11-11 11:35:46
【问题描述】:

我正在使用 Java JNA 库来调用我创建的 Delphi DLL。我正在使用的 Delphi 函数返回一个类型,它是一个 PAnsiChar 数组。我遇到的问题是,当我尝试在 Java 中调用该函数时,它给了我一个java.lang.Error: Invalid memory access

我的 Delphi 代码在这里:

function doTest(inputStatement: PAnsiChar): TDynamicAnsiCharArray; stdcall;
begin
  SetLength(result, 3);

  result[0] := 'Line 1';
  result[1] := 'Line 2';
  result[2] := 'Line 3';
end;

我的 Java 代码在这里:

public interface CLib extends StdCallLibrary {

    CLib INSTANCE = (CLib) Native.loadLibrary("DatabaseLibrary", CLib.class);
    public String[] doTest(String input);
}

public Main() {

    String[] dllOut = CLib.INSTANCE.doTest("Test?");
    for(int i = 0; i < dllOut.length; i++){
        System.out.println(dllOut[i]);
    }
}

完整的 Java 错误在这里:

Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokePointer(Native Method)
at com.sun.jna.Function.invokePointer(Function.java:470)
at com.sun.jna.Function.invoke(Function.java:430)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy0.doTest(Unknown Source)
at Main.<init>(Main.java:17)
at Main.main(Main.java:25)

第 17 行是带有 String[] 定义的行。

我有一种感觉,这种方式根本行不通,但我希望确实有办法。

【问题讨论】:

  • 你不能这样。您不能跨互操作边界返回 Delphi 字符串。你也不能返回动态数组。你需要找到另一种方法。通常这将涉及调用者分配内存。
  • 也许stackoverflow.com/q/10158582/80901 有帮助,它使用了Pointer JNA 类
  • 只是指出这一点,但我能够将单个 PAnsiChar 从 dll 传递回 Java。
  • 我已经查看了关于该主题的几乎所有 Stack Overflow 问题,但我似乎找不到任何可以正确显示如何在这两者之间以某种方式传递数据数组的任何问题。根据我所见,您可以在 Java 中声明一个数组,然后将其作为参数传递给 Delphi,Delphi 填充它并将其传回给 Java。但是,我找不到如何将这些数据实际获取到 java 变量中
  • 如果你想解决这个问题,这取决于你,但你可能做错了。您如何确保分配的缓冲区超出函数的生命周期?调用者如何释放函数分配的内存?

标签: java arrays delphi dll jna


【解决方案1】:

您没有告诉我们TDynamicAnsiCharArray 是什么,但我认为它是PAnsiChar 的动态数组:

type
  TDynamicAnsiCharArray = array of PAnsiChar;

这不是二进制互操作的有效类型。

在 Java 方面,您不能使用 String[] 作为返回值,原因大致相同。

有很多方法可以解决这个问题。没有一个是特别简单的。我认为也许最干净的方法是要求函数返回包含整个列表的单个字符串。您可能会使用一些粗略的东西,例如双空终止字符串。或者,您可以将列表序列化为 JSON 数组并返回该文本。对于这些选项中的任何一个,您只需要找到一种返回字符串的方法。

最干净的方法是让调用者分配内存。这个答案涵盖了该技术:How can I call a Delphi function that returns a string using JNA?

让调用者分配内存的另一种方法是使用在共享堆外分配的字符串类型。显而易见的选择是 COM BSTR 类型,Delphi 中的 WideString。这在 JNA 中表示为 WTypes.BSTR。请注意不要将其用作 WideString 函数返回值,因为 Delphi 不遵循平台 ABI:Why can a WideString not be used as a function return value for interop?

【讨论】:

    猜你喜欢
    • 2019-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多