Search code examples
javac++dlljna

Java: load c++ dll with char** and callback as parameters


I want to read some functions from a c++ dll in java.

This is a part of the dll code in c++:

typedef void(*E1)(int P1, char * P2);
__declspec(dllimport) void S11(int id, char* P1, E1 callback);
__declspec(dllimport) void Get_P1(int id, char** P1);

And this is the code to read the dll in java:

interface InterestingEvent
{
    public void interestingEvent(int id, String P1);
}

class Callback implements InterestingEvent {
    @Override
    public void interestingEvent(int id, String P1) {
        System.out.print("The the event "+ id + " throw this error: " + P1 + "\n");
    }
}
public class Main{

public interface Kernel32 extends Library {
    public void S11(int id, String P1, InterestingEvent callback);
    public void Get_P1(int id, String[] P1);
    }

public static void main(String[] args) {
    Kernel32 lib = (Kernel32) Native.loadLibrary("path\\to\\dll",
            Kernel32.class);
    lib.S11(id, "some string", new Callback() );
    }
}

And it returns me this error:

Exception in thread "main" java.lang.IllegalArgumentException: Unsupported argument type com.company.Callback at parameter 2 of function S11

what am I doing wrong?

And in the Get_P1 method a value is assigned to the parameter P1 and when return I want it to keep that value, similar to the parameters out in C#. What would be the correct way to invoke this method?


Solution

  • Your InterestingEvent interface needs to extend JNA's Callback interface (so rename your Callback class to something else). See Callbacks, Function Pointers and Closures for more details.

    As for the 2nd parameter of Get_P1(), use PointerByReference instead of String[]. See Using ByReference Arguments for more details. In this case, you can use PointerByReference.getValue() to get a Pointer representing the returned char* value, and then you can convert that to a String using Pointer.getString().

    Try this:

    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Callback;
    import com.sun.jna.ptr.PointerByReference;
    
    interface InterestingEvent extends Callback
    {
        public void interestingEvent(int id, String P1);
    }
    
    class MyCallback implements InterestingEvent {
        @Override
        public void interestingEvent(int id, String P1) {
            System.out.print("The the event "+ id + " throw this error: " + P1 + "\n");
        }
    }
    
    public class Main{
    
        public interface Kernel32 extends Library {
            public void S11(int id, String P1, InterestingEvent callback);
            public void Get_P1(int id, PointerByReference P1);
            }
    
        public static void main(String[] args) {
            Kernel32 lib = (Kernel32) Native.loadLibrary("path\\to\\dll",
                    Kernel32.class);
            lib.S11(id, "some string", new MyCallback() );
    
            PointerByReference p = new PointerByReference();
            lib.Get_P1(id, p);
            String str = p.getValue().getString(0);
        }
    }