JNA調用庫文件
阿新 • • 發佈:2018-09-03
sleep 我們 col als 生成 detail 一個 def xtend
最近項目中要集成廠商的卡口攝像頭,需要通過jna調用庫函數接收卡口相機抓拍的過車數據。本文記錄了Java調用C語言動態庫(jna)的調用方式、回調函數、結構體等。
JNA全稱Java Native Access,是一個建立在經典的JNI技術之上的Java開源框架,主要解決jni調用其他語言繁瑣的步驟。JNI是Java Native Interface的縮寫,它提供了若幹的api實現了Java和其他語言的通信(主要是c&c++).
jna 官方github:https://github.com/java-native-access/jna
下面來看看GettingStarted:
/** * GettingStarted *@author tangquanbin * @date 2018/8/28 15:39 */ public class HelloWorld { /** * 需要定義一個接口,繼承自Library 或StdCallLibrary * 默認的是繼承Library ,如果動態鏈接庫裏的函數是以stdcall方式輸出的,那麽就繼承StdCallLibrary */ public interface CLibrary extends Library { /** * 實例化接口,從而使用接口的方法,也就是調用外部dll/so的函數。 * * 第一個參數是動態鏈接庫dll/so的名稱,但不帶.dll或.so這樣的後綴,這符合JNI的規範,因為帶了後綴名就不可以跨操作系統平臺了。 * 搜索動態鏈 接庫路徑的順序是:先從當前類的當前文件夾找,如果沒有找到,再在工程當前文件夾下面找win32/win64文件夾, * 找到後搜索對應的dll文件,如果 找不到再到WINDOWS下面去搜索,再找不到就會拋異常了。 * 比如上例中printf函數在Windows平臺下所在的dll庫名稱是msvcrt,而在 其它平臺如Linux下的so庫名稱是c。 * * 第二個參數是本接口的Class類型。JNA通過這個Class類型,根據指定的.dll/.so文件, * 動態創建接口的實例。該實例由JNA通過反射自動生成。*/ CLibrary INSTANCE = (CLibrary)Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class); /** * 參數和返回值的類型,應該和鏈接庫中的函數類型保持一致。 * @param format * @param args */ void printf(String format, Object... args); } public staticvoid main(String[] args) { CLibrary.INSTANCE.printf("Hello, World\n"); for (int i=0;i < args.length;i++) { CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]); } } }
jna調用的方式上面代碼中的註釋已經寫得很清楚了,現在我們就來看看jna的函數調用、回調函數。
我們先來看看一般回調函數java的實現,其中加入了異步的思想,這也正是回調方法Callback最大的優勢:
現在有一個場景,學生A、B是同學,學生A有到題不會做就ask學生B。
1.會做題的接口
/** * 回調方法的優勢 * 回調方法最大的優勢在於,異步回調 * @author tangquanbin * @date 2018/8/30 15:54 */ public interface Slover { void slove(); }
2.學生B
/** * @author tangquanbin * @date 2018/8/30 15:58 */ public class StudentB implements Slover{ @Override public void slove() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("問題解決了"); } }
3.學生A
/** * @author tangquanbin * @date 2018/8/30 15:57 */ public class StudentA{ public void ask(Slover slover) { new Thread(new Runnable() { @Override public void run() { slover.slove(); } }).start(); goSomeThing(); }
public void goSomeThing(){ System.out.println("StudentB,我去做其他事了"); } }
測試
/** * @author tangquanbin * @date 2018/09/02 22:34 */ public class Test { public static void main(String[] args) { StudentA studentA = new StudentA(); studentA.ask(new StudentB()); } }
輸出:
StudentB,我去做其他事了
問題解決了
在JNA中回調方法要繼承Callback或者StdCallCallback
下面這部分參考自:https://blog.csdn.net/ggmove/article/details/17377117
列如dll接口函數及回調函數類型:
typedef void (*Callback_Status)(char *station_id, char *station_ip, int status); int Start_Server(char *ip, int port, Callback_Status fun);
java代碼->回調函數聲明:
public class getSDK { public interface Callback_Status extends StdCallCallback { public void Status(String station_id, String station_ip, int status); } }
java代碼->回調函數實現:
public class getSDK { public static class Status_Realize implements Callback_Status{ public void Status(String station_id, String station_ip, int status) { if (status == 2) { GUI.Station_online(station_id, station_ip, 1, 0); } else if (status == 3) { GUI.Station_online(station_id, station_ip, 2, 0); } } } }
jna調用還有一個重要的知識點:結構體Structure。時間不早了等下次再補充吧。
JNA調用庫文件