1. 程式人生 > >JNA調用庫文件

JNA調用庫文件

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 static
void 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調用庫文件