Search code examples
javadelphijna

Java Callback from Delphi using JNA crashes VM


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!


Solution

  • 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.