I am trying to implement a simple callback from Delphi to Java using JNA using the following java code:
package jnaapp;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Callback;
public class JnaAppTest {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "helloDelphi" : "c"),
CLibrary.class);
public interface eventCallback extends Callback {
public void callback(int id);
}
boolean setCallback(eventCallback callback);
boolean TestFunction(byte[] text, int length);
}
public static void main(String[] args) throws Exception{
byte[] text = new byte[100];
CLibrary.eventCallback callback = new CLibrary.eventCallback(){
public void callback(int id){
System.out.println("I was called with: "+id);
}
};
System.out.println(CLibrary.INSTANCE.setCallback(callback));
System.out.println(CLibrary.INSTANCE.TestFunction(text, 100));
System.out.println(Native.toString(text));
}
}
The corresponding Delphi code is given below:
Library helloDelphi;
uses
SysUtils,
Classes;
{$R *.res}
type TCallback = procedure(val: Integer); stdcall;
var
cb : TCallback;
function setCallback(callBack : TCallback) : WordBool; stdcall; export;
begin
cb := callBack;
Result := True;
end;
function TestFunction(stringBuffer : PAnsiChar; bufferSize : integer) : WordBool; stdcall; export
var s : string;
begin
s := 'Hello World 2';
StrLCopy(stringBuffer, PAnsiChar(s), bufferSize-1);
cb(bufferSize);
Result := True;
end;
exports TestFunction;
exports setCallback;
begin
end.
When the callback is called from Delphi, this crashes the VM. If I remove the callback from Testfunction, everything works fine! Thanks for your help!
Delphi uses the stdcall
calling convention, so you need to use StdCallLibrary
, not Library
. The wrong convention will cause a crash because the called function will be expecting to use a different stack layout than the calling code.
You'll also need to use StdCallCallback
rather than Callback
.