Search code examples
javac++type-conversionwrapperjna

How to work with C++ objects in JNA


I am trying to access a C++ library from Java using JNA. To do so I have written a thin wrapper around the C++ methods that I require. However, wrapping the C++ object, passing to Java and back to C++ results in Invalid Memory access while accessing the object in C++. Any pointers on why this is happening will be very helpful.

newencoder.h

Class Encoder {

public:
Encoder();
~Encoder();

template<class Type>
bool originalEncode(Type* input);

}

encoder_wrapper.h

typedef void* EncoderWrap;

    extern "C" {
    EncoderWrap newEncoder();

    const char* encode(EncoderWrap vcEncoder);
    }

encoder_wrapper.cpp

#include "encoder_wrapper.h"
#include "newencoder.h"

EncoderWrap newEncoder() {
    return reinterpret_cast<void*>(new Encoder());
}

const char* encode(EncoderWrap encoderObj) {
        std::string input;
        (reinterpret_cast<Encoder*>(encoderObj))->originalEncode(&input); //This is where the invalid memory access occurs. Commenting this line and returning a placeholder string does not throw any error.
        return input.c_str();
    }

JNA

private static class Encoder {

    public static native Pointer newEncoder();
    public static native String encode(Pointer encoderObj);

    static {
            Native.setProtected(true);
            Native.register("encoderlib");
    }

}

//Code that calls the native methods

Pointer encoderObj = Encoder.newEncoder(); //Does not fail
String result = Encoder.encode(encoderObj); //Results in Invalid Memory access

I tried calling the encode() method from within the C++ method newEncoder() and that works as expected. This memory error only happens when I receive the encoder object casted as void* in java and pass it back to the C++ method enocode().


Solution

  • I solved this by enclosing the void* in a structure and returning the structure to JNA. Every time the newEncoder is called, a structure instance is created which will have a new Encoder object casted as void* as a member.

    The struct object is passed to the encode function every time. This method in turn casts the void* back to the object and calls the originalEncode method.