1

I need to call a proprietary DLL function with the following prototype (simplified for clarity):

int J_Image_OpenStream(J_IMG_CALLBACK_OBJECT obj, J_IMG_CALLBACK_FUNCTION function);

The type definitions are:

class CJDummyClass
{
};
typedef CJDummyClass * J_IMG_CALLBACK_OBJECT;
typedef void (CJDummyClass::*J_IMG_CALLBACK_FUNCTION)(J_tIMAGE_INFO * pAqImageInfo);

I've worked with HOOKPROC callbacks before in JNA but not with Callback. It looks like I can't even use Callback here.

As I don't know how to extend class CJDummyClass inside Java, I just tried this:

public class MyCallback implements Callback {
    public void callback() { System.out.println("Here"); }
}

MyCallback callback = new MyCallback();
lib.J_Image_OpenStream(callback.getClass, callback);

It gives: IllegalArgumentexception: Unsupported argument type java.lang.Class at parameter 0 of function J_Image_OpenStream

Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50
  • That's a member function pointer. You're not going to get that working with JNA. Check here for a solution with JavaCPP: http://stackoverflow.com/a/25934842/523744 – Samuel Audet Oct 05 '14 at 00:03

1 Answers1

1

Short answer: you can't (assuming you're truly talking C++ and not C)

I'll simplify things a bit since it seems you'd like a deeper understanding of both C++ and Java classes.

A class in C++ comprises a lot of different details, but you can think of it as a bundle of function pointers, each of which has an implicit first argument which represents the object that is an instantiation of the class. When you create an instance of that class, you get a box full of stuff that includes object data and a reference to those function pointers. Every C++ compiler puts these things together in a slightly different fashion.

You can think of the class on the Java side to have roughly the same concepts, but implemented in an entirely different way. In order to get the Java class to pretend that it's the same as a C++ class, you have to know how the native compiler put things together, and how to translate each piece of your Java class into a corresponding piece in the C++ class. Not everything translates, and while you can map a lot of common things, it's a significant amount of work and most easily done by incorporating the native compiler into the task (see JavaCPP reference below).

Other solutions exist that allow you to define classes in Java which use JNI to communicate with similarly-defined classes in C++. Unfortunately, they involve some amount of writing and/or compiling native code and glueing that to the Java bits.

SWIG JavaCPP

Now, if you're talking about calling a function that uses only C data types (including function pointers aka callbacks), then JNA will absolutely be able to do what you want. The C language uses a well-defined method for making functions available from a shared library. As long as you know the function name and line up the arguments in the right order, you can use that shared library from just about any language. JNA uses that well-defined structure of shared libraries to automatically convert your Java primitive data types (and some composite ones like Structure) to successfully call methods within your shared library.

technomage
  • 9,861
  • 2
  • 26
  • 40
  • Yeah I already gave a working JNI implementation, but and my superiors tasked me by converting each and every JNI project to JNA. This Is the last one remaining. – Mark Jeronimus Oct 04 '14 at 21:32
  • So, It's easy to use jna to call a method from a shared library when this methods contains arguments when can be represented by java native code, but what about a method that takes unique arguments like (structs), how can I pass arguments to such methods from my java code using jna? – Muhammed Refaat Dec 25 '14 at 14:45
  • JNA will accommodate [`struct`, `struct*`](https://github.com/twall/jna/blob/master/www/StructuresAndUnions.md), arrays and other aggregate data types. It will *not* do C++ classes without a fair bit of extra work. – technomage Dec 26 '14 at 14:23