簡介:
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");
}
}
入坑點:
-
關于JNA調用32位和64位動態鏈接庫,即*.dll
影響JNA加載動態庫成功的因素 查找動態鏈接庫路徑的順序:
- 先從當前類的當前文件夾找,
- 如果沒有找到,再在當前工程目錄中查找,找到后搜索對應的dll文件,-
- 如果找不到,再到C盤 Windows目錄下面去查找(主要在System32、SysWOW64目錄中查找)
- 再找不到就會拋異常
Windows 64bit操作系統,System32文件夾下的dll是64位版本的,而SysWOW64文件夾下的dll其實是32位版本的
注:SysWOW64 全稱:32bit Windows On 64bit Windows(64位Windows上的32位Windows)有的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);
}