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

I am working on a java project to run on both Windows and Linux, and I am using a third-party shared library available to both operating systems with the same method signature. But the dll calling convention is stdcall, and the common object is cdecl.

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

The only change in the code below for .so access on linux is the interface. The callback function code itself is the same. I would appreciate any suggestion.

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

This is the code I wrote for the dll callback:

 //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

+6
source share
2 answers

You can declare both of them with StdCallLibrary / StdCallCallback, but the behavior may not be defined on all platforms. The option is ignored on platforms that do not support an alternative calling convention (that's all except win32 at the moment), but was not necessarily tested on all platforms.

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

 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 just target Linux and windows, then one interface might be enough (I would recommend checking this out though):

 interface MyLibrary extends StdCallLibrary { interface MyCallback extends StdCallCallback { public void invoke(); } void callbackFunction(MyCallback cb); MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", MyLibrary.class); } 
+3
source

I would have a different wrapper around JNAWrapper. So, for example, if the JNA shell for dll is called IExternLibWindows , and one for Linux is called IExternLibLinux , I would write another shell - IExternLib . Then,

  public interface IExternLibWindows extends StdCallLibrary{ public IExternLibWindows Instance ; ... void stdcall_somefunc(...); ... } public interface IExternLibLinux extends StdCallLibrary{ public IExternLibLinux Instance ; ... void cdecl_somefunc(...); ... } public class IExternLib(){ public void somefunc(...){ if(System.getProperty("os.name").startsWith("Windows")) IExternLibWindows.stdcall_somefunc(...); else if(System.getProperty("os.name").startsWith("Linux")) IExternLibLinux.cdecl_somefunc(...); } } 
0
source

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


All Articles