C ++ non-static callbacks and JNA

I am trying to use the C ++ API in Java with JNA. This API uses callbacks to handle session events.

The only resource I found on how to register callbacks with JNA is and it deals with C callbacks, and I don’t really know how to extend this to non-static C ++ callbacks.

EDIT: I found this resource , I think the chapter “Revisiting Callbacks” can help.

All function pointers for callbacks are stored in the following sp_session_callbacks structure:

 /** * Session callbacks * * Registered when you create a session. * If some callbacks should not be of interest, set them to NULL. */ typedef struct sp_session_callbacks { void (__stdcall *logged_in)(sp_session *session, sp_error error); void (__stdcall *logged_out)(sp_session *session); void (__stdcall *connection_error)(sp_session *session, sp_error error); void (__stdcall *message_to_user)(sp_session *session, const char *message); // Other callbacks function pointers } sp_session_callbacks; 

The generated Java class described in this structure is as follows:

 public class sp_session_callbacks extends Structure{ public Function logged_in; public Function logged_out; public Function connection_error; public Function message_to_user; } 

Does it make sense to represent pointers to com.sun.jna.Function functions in this case, in your opinion?

Each session is represented by an sp_session object, which is an opaque C ++ structure. I have a handle to the sp_session_callbacks object when I initialize it.

Here is a snippet of code from my main class:

 JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class); sp_session_config cfg = new sp_session_config(); /* Some cfg config here */ sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object cfg.callbacks = sessCallbacks; PointerByReference sessionPbr = new PointerByReference(); int errorId = lib.sessionCreate(cfg, sessionPbr); sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object 

How do I register the callbacks function to actually do something on the Java side when they start?

Thanks!

EDIT

New code using callback instead of function:

 public class sp_session_callbacks extends Structure{ public LoggedIn logged_in; /* Other callbacks... */ } public interface LoggedIn extends StdCallCallback { public void logged_in(sp_session session, int error); } 

Main class:

 JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class); sp_session_config cfg = new sp_session_config(); /* Some cfg config here */ sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object LoggedIn loggedInCallback = new LoggedIn(){ public void logged_in(sp_session session, int error){ System.out.println("It works"); } }; sessCallbacks.logged_in = loggedInCallback; /* Setting all the other callbacks to null */ cfg.callbacks = sessCallbacks; PointerByReference sessionPbr = new PointerByReference(); int errorId = lib.sessionCreate(cfg, sessionPbr); sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object 

Calling sessionCreate () causes a false JRE error (EXCEPTION_ACCES_VIOLATION 0x0000005) when cfg.logged_in is not null but an instance of LoggedIn. The strange thing is that the 2 callbacks logged_in and the connection error have the same signature, and when cfg.connection_error is set, it throws nothing.

+4
source share
2 answers

From a function, javadoc is its own method, if you want to call the java method, you need to create a Callback for each function pointer.

If you use only java callbacks and there are no native functions, you can simply replace the function with a callback. (Depending on the calling convention used, you may use StdCallLibrary.StdCallCallback instead)

 public class sp_session_callbacks extends Structure{ public StdCallCallback logged_in; public StdCallCallback logged_out; public StdCallCallback connection_error; public StdCallCallback message_to_user; } sp_session_callbacks calls = new sp_session_callbacks(); calls.logged_out = new StdCallCallback(){ public void someName(sp_session sp){...} } 
+2
source

In principle, in order to associate a callback of any type with a member function of an object, it had to pass the objective function and the object instance to satisfy this first invisible parameter. The problem here is that JNA accepts only a specific function format. Therefore, you should solve the problem whenever possible. Unfortunately, in C ++ this can lead to the use of temporary global variables, but as long as you focus on passing control back to the object, you can maintain a good OO design.

This has nothing to do with the "C vs C ++" thing. You just need to understand what the member function calls, and basically what it compiles.

 myObject.memberFunction(); // This is what the programmer sees. memberFunction(&myObject); // This is what the compiler sees. 

A member function is a fancy description of a function that simply takes an object as its first parameter. It is simply invisible in the list of actual parameters.

 void MyClass::memberFunction() // This is the declaration the programmer sees. void memberFunction(MyClass* this) // This is what the compiler sees. 

From there, C ++ adds special semantics that make it easier to work in object-oriented mode.

In short, you will almost never be able to directly connect to the member function of an object until JNA itself has added mechanisms for this.

0
source

Source: https://habr.com/ru/post/1342287/


All Articles