Search code examples
javacwrapperjna

JNA callback function with additional argument


I have got problem getting JNA all worked out. I am trying to invoke a function that takes as a arguments pointer to function and const char*. My C code looks like this:

typedef void (*example_ptr)(const char*);

void exampleMethod(const char* value)
{
    printf("This is the string: %s\n", value);
}

void example_triggerCallback(const example_ptr func, const char* str) {
    printf("provided str: %s", str);
    func(str);
}

To get this going I wrote such JNA wrapper in Java

public class Main {

    public interface TestLibrary extends Library {

        TestLibrary INSTANCE = (TestLibrary)
                Native.loadLibrary("libtest",
                        TestLibrary.class);

        interface ExampleCallback extends Callback {
            void invoke(String str);
        }

        class ExampleCallbackImpl implements ExampleCallback {
            public void invoke(String str) {
                System.out.println("example: " + str);
            }
        }

        void example_triggerCallback(ExampleCallback callback, String str);
    }

    public static void main(String[] args) {

        TestLibrary testLibrary = TestLibrary.INSTANCE;
        final TestLibrary.ExampleCallbackImpl callback = new TestLibrary.ExampleCallbackImpl();
        testLibrary.example_triggerCallback(callback, "testiddy test test");
    }
}

The problem I am facing is that the printf in example_triggerCallback in C code is in fact being called and I am getting the output on Java console but what I am really trying to achieve here is that I would like to pass from Java side the pointer for the exampleMethod from C so it would be printing the passed String. Right now func(str) seems to be ignored. What am I missing here?


Solution

  • Based on something found in JNA documentation:

    typedef void (*ExampleCallback)(const char*);
    
    void exampleMethod(const char* value)
    {
        printf("This is the string: %s\n", value);
    }
    
    void example_triggerCallback(const example_ptr func, const char* str) {
        printf("provided str: %s", str);
        func(str);
    }
    
    public interface CLibrary extends Library {
        // define an interface that wraps the callback code
        public interface ExampleCallbackInterface extends Callback {
            void invoke(String val);
        }
    
            // functions available in library (name must match)
        public void exampleMethod(String  value);
        public void example_triggerCallback(ExampleCallbackInterface callback);
    }
    
    // define an implementation of the callback interface
    public static class CallbackExample implements Example22CallbackInterface {
        private CLibrary lib;
    
        public CallbackExample(CLibrary useLib) {
            lib = useLib;
        }
    
        @Override
        public void invoke(String val) {
            lib.exampleMethod(val);
        }
    }
    
    ...
    final CLibrary clib = (CLibrary)Native.loadLibrary("testlib", CLibrary.class);
    ...
    // instantiate a callback wrapper instance
    final CallbackExample callback = new CallbackExample(clib);
    
    // pass the callback wrapper to the C library
    clib.example_triggerCallback(callback);
    

    Since I answered this question in some other internet location, I know that it works for the questioner.