1. 程式人生 > >JNA呼叫C語言動態連結庫學習實踐總結(指標模擬)

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好用多了。