使用JNA庫調用dll/so 動態庫

簡介:

JNA全稱:Java Native Access,是一款在JNI層做了封裝,為了簡捷方便讓開發者調用動態庫的開源庫。

流程:

  • 首先去JNA在GitHub中的主頁下載最新的jna核心 jar包何platform jar包,目前最新的是版本是jna-5.2.0、jna platform-5.2.0
  • 寫一個interface TestDll 繼承 jna包里面的 Library / StdCallLibrary 接口,代碼如下:
public interface TestDll extends Library{
   // 聲明一個實例,加載動態庫并持有庫的引用
   String dllPath = "msvcrt";  //動態庫的路徑,如 window是系統自帶的msvcrt.dll【可不需要帶動態庫后綴,JNA庫會自動識別動態庫的類型】
   TestDll INSTANCE = Native.load(dllPath, TestDll.class);

  // 聲明一個方法,來映射native方法,通過調用該方法實現調用native 方法,
 // 示例 msvcrt.dll中定義的一個void printf(String format, Object... objects)方法:
  void printf(String format, Object... objects);
}
  • 然后在Java代碼中調用printf()方法
public class Test{
    public static void main(String[] args){
        // 方式1:調用native printf()方法
        TestDll.INSTANCE.printf("Hello World");
        
       // 方式2:調用native printf()方法
      TestDll testDll = Native.load("msvcrt.dll", TestDll.class);
      testDll.printf("Hello World");
  }
}

入坑點:

  1. 關于JNA調用32位和64位動態鏈接庫,即*.dll


    影響JNA加載動態庫成功的因素
  2. 查找動態鏈接庫路徑的順序:

  • 先從當前類的當前文件夾找,
  • 如果沒有找到,再在當前工程目錄中查找,找到后搜索對應的dll文件,-
  • 如果找不到,再到C盤 Windows目錄下面去查找(主要在System32、SysWOW64目錄中查找)
  • 再找不到就會拋異常
  1. Windows 64bit操作系統,System32文件夾下的dll是64位版本的,而SysWOW64文件夾下的dll其實是32位版本的
    注:SysWOW64 全稱:32bit Windows On 64bit Windows(64位Windows上的32位Windows)

  2. 有的c / c++語言定義的函數的參數用到了struct(結構體),例如kernel32.dll庫里面的 void GetLocalTime()函數:

typedef struct {
WORD wYear; 
WORD wMonth; 
WORD wDayOfWeek; 
WORD wDay; 
WORD wHour; 
WORD wMinute; 
WORD wSecond; 
WORD wMilliseconds; 
} SYSTEMTIME, *LPSYSTEMTIME;
VOID GetLocalTime(LPSYSTEMTIME lpst);

在Java中需要定義一個類繼承 jna包里面的Structure類,作為Java中的結構體,代碼如下:

public static class SystemTime extends Structure {
        public short wYear;
        public short wMonth;
        public short wDayOfWeek;
        public short wDay;
        public short wHour;
        public short wMinute;
        public short wSecond;
        public short wMilliseconds;
        
        /*【關鍵坑點】:這里必須重寫getFieldOrder()方法,明確結構體中涉及字段的名稱和聲明次序,
          為了確保執行native方法,能正確的賦值內容給各字段
          如果不這樣重寫,會報jna的一個異常
       */
        @Override
        protected List<String> getFieldOrder() {
            // TODO Auto-generated method stub
            System.out.println("重寫getFieldOrder()方法");
            return Arrays.asList("wYear","wMonth","wDayOfWeek","wDay","wHour","wMinute","wSecond","wMilliseconds");
          } 
       }


        @Override
        protected List<Field> getFieldList() {
            return super.getFieldList();
        }

    // 結構體作為函數參數時,以引用(即指針)形式傳遞參數
    public static class ByReference extends CommData implements Structure.ByReference { }

    // 結構體作為函數參數時,以值傳遞形式傳遞參數
    public static class ByValue extends CommData implements Structure.ByValue{}

    // 聲明要調用native方法的一個方法接口
    void GetLocalTime(SystemTime result);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。