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