【问题标题】:How to use JNA in .dll and .so with the same callback signature如何在具有相同回调签名的 .dll 和 .so 中使用 JNA
【发布时间】:2011-06-02 20:03:50
【问题描述】:

我正在开发一个可在 Windows 和 Linux 上运行的 java 项目,并且我正在使用具有相同方法签名的两个操作系统都可用的第三方共享库。但是,dll的调用约定是stdcall,而共享对象是cdecl。

我想避免重复回调代码,两个接口和两个类,每个调用约定一个接口。我想为回调函数编写一个代码。这可能吗?

在下面的代码中,在 linux 中访问 .so 的唯一变化是接口。回调函数代码本身也是一样的。我会很感激任何建议。

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

谢谢,

费尔南多

【问题讨论】:

    标签: java linux dll callback jna


    【解决方案1】:

    您可以使用 StdCallLibrary/StdCallCallback 声明它们,但可能并非在所有平台上都定义了该行为。该选项在不支持备用调用约定的平台上被忽略(目前是除 win32 之外的所有平台),但不一定在所有平台上都经过测试。

    这是首选定义,它只为 windows 定义 stdcall 库。

    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);
    }
    

    【讨论】:

    • 嗨,你能举个例子吗?
    • 注意上面的变化,即除了windows不要使用StdCallLibrary。
    【解决方案2】:

    我会在 JNAWrapper 周围有另一个包装器。例如,如果 dll 的 JNA 包装器称为 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(...);
    
        }
     }
    

    【讨论】:

    • technomage 的响应更符合 KISS 标准,因为它可以防止代码乘法和可避免的 if(当你需要实现 somefunc2 时你会怎么做)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 2014-05-06
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    相关资源
    最近更新 更多