Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use JNA in .dll and .so with the same callback signature

I'm working on a java project to run on both Windows and Linux, and I'm using a third party shared library available to both operating systems with the same methods' signature. But, the dll's calling convention is stdcall while the shared object is cdecl.

I'd like to avoid duplicate the callback code, two interfaces and two classes, one interface for each calling convention. I would like to write a single code for the callback function. Is that possible?

The only change in the code below to access .so in linux is the interface. The callback function code itself is the same. I'll appreciate any sugestion.

import com.sun.jna.Callback;
interface IExternLibCallback extends Callback {..}

This is the code that I wrote for the callback in dll:

//Interface to stdcall (Windows)
package test1;
import com.sun.jna.win32.StdCallLibrary;
interface IExternLibCallback extends StdCallLibrary.StdCallCallback  {

      void callback (JEventDataStructure context_data);
}

//Class that implements the interface
package test1;
class ExternLibCallback implements IExternLibCallback  {

     ... Other class codes go here ....

  @ Override
  public void callback (JEventDataStructure contextData) {

     ... Code of callback function
  }
}

Thanks,

Fernando

like image 681
Fernando Avatar asked Jun 02 '11 20:06

Fernando


1 Answers

You can declare them both with StdCallLibrary/StdCallCallback, but the behavior might not be defined on all platforms. The option is ignored on platforms that don't support an alternate calling convention (which is everything except win32 at the moment), but hasn't necessarily been tested on all platforms.

This is the preferred definition, which defines the stdcall library only for windows.

interface MyLibrary extends Library {
   interface MyCallback extends Callback {
       public void invoke();
   }
   void callbackFunction(MyCallback cb);
   MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", Platform.isWindows() ? MyWin32Library.class : MyLibrary.class);
}
interface MyWin32Library extends MyLibrary, StdCallLibrary {
   interface MyStdCallCallback extends MyCallback, StdCallCallback {}
   void callbackFunction(MyStdCallCallback cb);
}

If you're just targeting linux and windows, then a single interface may suffice (I'd recommend testing this, though):

interface MyLibrary extends StdCallLibrary {
   interface MyCallback extends StdCallCallback {
       public void invoke();
   }
   void callbackFunction(MyCallback cb);
   MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", MyLibrary.class);
}
like image 171
technomage Avatar answered Oct 15 '22 23:10

technomage