Java 使用JNA 呼叫dll動態庫檔案
Java 呼叫 DLL 無非三種方法:JNI、JNA、JNative
1 JNA是什麼
JNA(JavaNativeAccess)框架是一個開源的Java框架,是SUN公司主導開發的,建立在
經典的JNI的基礎之上的一個框架。
JNA專案地址:https://jna.dev.java.net/
JNA使Java呼叫原生函式就像.NET上的P/Invoke一樣方便、快捷。
JNA的功能和P/Invoke類似,但編寫方法與P/Invoke截然不同。JNA沒有使用Annotation,
而是通過編寫一般的Java程式碼來實現。
P/Invoke是.NET平臺的機制。而JNA是Java平臺上的一個開源類庫,和其他類庫沒有
JNA使Java平臺可以方便地呼叫原生函式,這大大擴充套件了Java平臺的整合能力。
2 新建專案,新增依賴
快速搭建一個springboot 專案,在pom檔案中加入
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>4.5.1</version> </dependency> <dependency> <groupId>com.sun.jna</groupId> <artifactId>jna</artifactId> <version>3.0.9</version> </dependency>
3 Java 程式碼呼叫
首先看dll檔案中定義的函式
//dll 檔案中初始化函式
int INIT(char * pErrMsg)
新建一個類,類中新增下面介面,SiInterface 為dll檔案,可以去掉字尾.dll
public interface SiInterface extends Library { // DLL檔案預設路徑為專案根目錄,若DLL檔案存放在專案外,請使用絕對路徑。(此處:(Platform.isWindows()?"SiInterface":"c")指本地動態庫msvcrt.dll) SiInterface INSTANCE = (SiInterface) Native.loadLibrary( "SiInterface.dll", SiInterface.class); // 宣告將要呼叫的DLL中的方法 public int INIT(byte[] input); }
main方法測試
public static void main(String[] args) throws Exception {
//INIT函式,引數是一個char*型別的可讀寫引數,需要用byte[]型別
byte[] outData = new byte[2048];
int code = SiInterface.INSTANCE.INIT(outData);
System.out.println(code);
String result = Native.toString(outData,"gbk");
System.out.println(result);
}
至此,呼叫dll的編碼工作已經完成,是不是很簡單 ,這都是sun公司大佬寫的jna框架好用,但實戰中其實會出現一些問題,下面總結一下
問題總結:
1 :java jna 報錯:Unable to load library
這個錯真讓人頭大,這個錯誤很明顯是無法載入到指定的動態連結庫,但是為什麼無法載入確沒有具體顯示出來,是路徑不對呢,還是dll的平臺與當前jvm的平臺不匹配沒有在錯誤資訊中顯示出來。所以需要一步一步排除找原因。
1)首先你要明確知道這個dll動態連結庫是32位的還是64位的編譯的,與之對應的就是你的java版本也是要對應的32位或者64位的。
2)確認了第一點那麼基本的環境就沒問題了,然後是填寫路徑,一般路徑可以是填相對路徑還是絕對路徑,為了避免可能出現未知錯誤,強烈建議還是填寫絕對路徑,絕對路徑要是反斜槓"\",為了避免出錯可以直接在IDE工具裡面找到對應的dll檔案右鍵copy path
貼上到載入dll路徑的方法裡作為引數,效果如下圖2.2
3)前面兩步如果可以保證正確的話,那麼基本上是可以載入成功的,如果還是失敗那請再回去驗證前面的步驟,如驗證j程式執行是不是在你預期的jvm之上
點選執行程式看看當前執行的jdk版本是哪一個,如下圖3.1
圖3.1
接下來就是cmd,執行java -version,看下圖3.2所示的jdk版本是32位,未顯示預設32位的,還是64位。jdk版本一致,且是64位,那麼與我的dll是相同的平臺,
那麼可以驗證下dll是不是64位或者32位就好了,驗證方法自行百度或者參照這位博主的https://www.cnblogs.com/Czhenyu/p/6439383.html
最後就是路徑問題了,如果你是按照我的操作來的那麼路徑就不會有問題,應該是正常執行的。
4)到這一步,你的程式還是無法載入dll檔案的話,我只能提供思路就是,你的dll是否還引用了其它的dll檔案,其它的dll檔案的平臺與當前不一致。或者找你得到dll來源,確認這個dll是否可以用,dll檔案時可以用visual studio 2017或其它把版本工具用C#程式碼直接引用呼叫的,當然你也可以用哪個工具打包一個dll。
檢視dll檔案位數還有一個簡便方法(當然可以問提供dll檔案之人最快,人家開發的嘛):
用txt或notepad 以記事本的方式開啟,亂碼沒關係,如果第二段PE 後面那個為L ,則是32位的,否則為64位 ,
最後總結一下:1.平臺要一致,平臺要一致,平臺要一致,重要的事情說三遍。
2.路徑問題,最好是絕對路徑。
剩下就是介面業務問題, 等待你的又是漫長的除錯。。。。。。。