1. 程式人生 > 其它 >Java 使用JNA 呼叫dll動態庫檔案

Java 使用JNA 呼叫dll動態庫檔案

技術標籤:javajavac++

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平臺上的一個開源類庫,和其他類庫沒有

什麼區別。只需要在classpath下加入jna.jar包,就可以使用JNA。
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.路徑問題,最好是絕對路徑。

剩下就是介面業務問題, 等待你的又是漫長的除錯。。。。。。。