I'm using the Java JNA library to call a Delphi DLL that I have created. The Delphi function I'm using returns a type that is an array of PAnsiChar. The problem I'm getting is that when I try and call that function in Java, it's giving me a java.lang.Error: Invalid memory access
.
My Delphi code is here:
function doTest(inputStatement: PAnsiChar): TDynamicAnsiCharArray; stdcall;
begin
SetLength(result, 3);
result[0] := 'Line 1';
result[1] := 'Line 2';
result[2] := 'Line 3';
end;
My Java code is here:
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]);
}
}
The full Java error is here:
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)
Line 17 is the line with the String[] definition.
I have this feeling that it's not going to work at all this way, but I'm hopeful there is actually a way.
You did not let us know what TDynamicAnsiCharArray
is but I presume it is a dynamic array of PAnsiChar
:
type
TDynamicAnsiCharArray = array of PAnsiChar;
That is not a valid type for binary interop.
On the Java side, you cannot use String[]
as a return value, for much the same reason.
There are lots of ways you might tackle this. None is particularly simple. I think that perhaps the cleanest is to ask the function to return a single string containing the entire list. You might use something crude like double null-terminated strings. Or you might serialize the list to a JSON array and return that text. For either of those options you just need to find a way to return a string.
The cleanest way to do that is to have the caller allocate the memory. This answer covers that technique: How can I call a Delphi function that returns a string using JNA?
An alternative to having the caller allocate the memory is to use a string type that is allocated off a shared heap. The obvious choice is the COM BSTR
type, WideString
in Delphi. That is represented as WTypes.BSTR
in JNA. Be careful not to use that as a WideString
function return value though because Delphi does not follow the platform ABI: Why can a WideString not be used as a function return value for interop?