Как использовать JNA в .dll и .so с одинаковой сигнатурой обратного вызова - PullRequest
6 голосов
/ 03 июня 2011

Я работаю над Java-проектом для запуска в Windows и Linux и использую стороннюю разделяемую библиотеку, доступную для обеих операционных систем с одинаковыми сигнатурами методов.Но соглашение о вызовах dll - это stdcall, а общим объектом - cdecl.

Я бы хотел избежать дублирования кода обратного вызова, двух интерфейсов и двух классов, по одному интерфейсу для каждого соглашения о вызовах.Я хотел бы написать один код для функции обратного вызова.Это возможно?

Единственное изменение в приведенном ниже коде для доступа к .so в linux - это интерфейс.Сам код функции обратного вызова такой же.Я буду признателен за любые предложения.

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

Это код, который я написал для обратного вызова в 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
  }
}

Спасибо,

Фернандо

Ответы [ 2 ]

3 голосов
/ 01 июля 2011

Вы можете объявить их обоих с помощью StdCallLibrary / StdCallCallback, но поведение может быть не определено на всех платформах.Эта опция игнорируется на платформах, которые не поддерживают альтернативное соглашение о вызовах (которое на данный момент является всем, кроме win32), но не обязательно были протестированы на всех платформах.

Это предпочтительное определение, котороеОпределяет библиотеку stdcall только для 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);
}

Если вы нацеливаетесь только на Linux и Windows, тогда единственного интерфейса может хватить (хотя я бы рекомендовал проверить это):

interface MyLibrary extends StdCallLibrary {
   interface MyCallback extends StdCallCallback {
       public void invoke();
   }
   void callbackFunction(MyCallback cb);
   MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", MyLibrary.class);
}
0 голосов
/ 03 июня 2011

У меня была бы другая обертка вокруг JNAWrapper.Так, например, если оболочка JNA для dll называется IExternLibWindows, а оболочка для Linux - IExternLibLinux, я бы написал другую оболочку - IExternLib.тогда

 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(...);

    }
 }
...