JNA呼叫C語言動態連結庫學習實踐總結(指標模擬)
最新因為專案需要,學習了一下JNA框架,在這裡記錄一下學習和使用心得,給大家分享,希望能幫助新手。
本文主要講解如何使用JNA框架輕鬆呼叫C語言動態連結庫,如何使用JNA模擬C語言引數(例如陣列、指標等)。
JNA(Java Native Access)框架是一個開源的Java框架,是SUN公司主導開發的,建立在經典的JNI的基礎之上的一個框架。
JNA官網地址:https://github.com/twall/jna
官網上有很多例子和學習入門教程,建議認真閱讀,很有幫助,比自己網路上到處搜尋效果好多了。
Maven專案引入JNA:
[html] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
<!--Java JNA -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.1.0</version>
</dependency>
引入JNA:
import com.sun.jna.*;
import com.sun.jna.ptr.*;
1.構造JNA模擬類
C語言函式:
void function1(int a, int b, const unsigned char* data);
char * function2(float * pVal, char * outString);
void function3(Rect * pRect, Rect rect);
JNA模擬:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
public interface MyLibTest extends Library {
//定義結構體
public static class Rect extends Structure {
//公共欄位的順序,必須與C語言中的結構的順序一致,否則會報錯!
public int left;
public int top;
public int right;
public int bottom;
//結構體傳指標
public static class ByReference extends Rect implements Structure.ByReference { }
//結構體傳值
public static class ByValue extends Rect implements Structure.ByValue{ }
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"left", "top", "right", "bottom"});
}
//載入庫檔案
MyLibTest INSTANCE = (MyLibTest) Native.loadLibrary("C:\libTest\CLib.dll",MyLibTest.class);
//函式模擬
void function1(int a, int b, char[] data);
String function2(FloatByReference fRef, char [] outString);
void function3(Rect.ByReference pRect, Rect.ByValue rect);
}
呼叫方式:
char[] arr1 = new char[陣列大小];
function1(1, 2, arr1);
char[] arr2 = new char[陣列大小];
FloatByReference fRef = new FloatByReference(0.1F);
String result = function2(fRef, arr2);
Rect.ByReference pRect = new Rect.ByReference(); //指標物件
Rect.ByValue rect = new Rect.ByValue(); //傳值物件
function3(pRect, rect);
2.JNA模擬普通傳值引數
C語言函式:
int function1(int a, float b, long c)
JNA模擬:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
int function1(int a, float b, long c)
3.JNA模擬C語言陣列
C語言函式:
void function1(char * data)
void function2(const unsigned char* data)
JNA模擬:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
void function1(char[] data) 或者 void function1(byte[] data)
void function2(char[] data) 或者 void function2(byte[] data)
4.JNA模擬基本型別指標
JNA的ByReference有很多子類,這些類都在com.sun.jna.ptr包中:
IntByReference,LongByReference,FloatByReference,DoubleByReference,ShortByReference、ByteByReference、PointerByReference等等
從這些名字大家應該可以看出來他們的作用。
下面直接上例子吧:
C語言函式:
long function(int * a, long * b, float * c, double * d, short * e)
JNA模擬:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
long function(IntByReference aRef, LongByReference bRef, FloatByReference cRef, DoubleByReference dRef, ShortByReference eRef)
如何構建這些物件呢?
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
FloatByReference cRef = new FloatByReference(); //使用預設初始值(具體多少我也不知道)
FloatByReference cRef = new FloatByReference(0); //初始值為0
呼叫方法和普通引數一樣:
function(..., cRef, ...);
獲取結果值:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
float fVal = cRef.getValue();
JNA都為我們做的很簡單,不是嗎?大笑
5. JNA模擬指標、指標的指標、模擬void ,void * 等指標
C函式:
void function(int * pInt, int ** ppInt, void * pVoid, void ** ppVoid)
JNA模擬:
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
void function(IntByReference pInt, PointerByReference ppInt, Pointer pVoid, PointerByReference ppVoid)
呼叫舉例:
IntByReference pInt = new IntByReference(0);
PointerByReference ppInt = new PointerByReference(Pointer.NULL);
//指向指標的指標,初始化為NULL
Pointer pVoid = Pointer.NULL; //建立一個指向NULL的指標
PointerByReference ppVoid = new PointerByReference(Pointer.NULL);
呼叫:function(pInt, ppInt, pVoid, ppVoid);
(1)PointerByReference是指向指標的指標,遇到指標的指標都可以使用它來模擬,那麼如何獲取到它指向的指標呢?
Pointer p = ppVoid.getValue(); //獲取指標
(2)如何獲取指標的指標呢?
[java] view plaincopy在CODE上檢視程式碼片派生到我的程式碼片
Pointer p1 = ....;
PointerByReference pp1 = new PointerByReference(p1);
PointerByReference ppp1 = new PointerByReference(pp1.getPointer());
這些操作大家可以自己做實驗嘗試,對於PointerByReference物件,getValue()是取值,而getPointer()是取這個指標的指標。
看著複雜,其實都很簡單!JNA要比JNI好用多了。