使用JNA庫調(diào)用dll/so 動態(tài)庫

簡介:

JNA全稱:Java Native Access,是一款在JNI層做了封裝,為了簡捷方便讓開發(fā)者調(diào)用動態(tài)庫的開源庫。

流程:

  • 首先去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{
   // 聲明一個實例,加載動態(tài)庫并持有庫的引用
   String dllPath = "msvcrt";  //動態(tài)庫的路徑,如 window是系統(tǒng)自帶的msvcrt.dll【可不需要帶動態(tài)庫后綴,JNA庫會自動識別動態(tài)庫的類型】
   TestDll INSTANCE = Native.load(dllPath, TestDll.class);

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

入坑點:

  1. 關(guān)于JNA調(diào)用32位和64位動態(tài)鏈接庫,即*.dll


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

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

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

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中的結(jié)構(gòu)體,代碼如下:

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;
        
        /*【關(guān)鍵坑點】:這里必須重寫getFieldOrder()方法,明確結(jié)構(gòu)體中涉及字段的名稱和聲明次序,
          為了確保執(zhí)行native方法,能正確的賦值內(nèi)容給各字段
          如果不這樣重寫,會報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();
        }

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

    // 結(jié)構(gòu)體作為函數(shù)參數(shù)時,以值傳遞形式傳遞參數(shù)
    public static class ByValue extends CommData implements Structure.ByValue{}

    // 聲明要調(diào)用native方法的一個方法接口
    void GetLocalTime(SystemTime result);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容