JNA 相關問題

JNA 相關問題

結構體對齊問題

要注意調用的c庫字段對齊方式的相關設置。html

#pragma  pack (push,1)

#pragma pack(pop)

jna中提供了4種對齊方式:java

/** Use the platform default alignment. */
    public static final int ALIGN_DEFAULT = 0;
    /** No alignment, place all fields on nearest 1-byte boundary */
    public static final int ALIGN_NONE = 1;
    /** validated for 32-bit x86 linux/gcc; align field size, max 4 bytes */
    public static final int ALIGN_GNUC = 2;
    /** validated for w32/msvc; align on field size */
    public static final int ALIGN_MSVC = 3;

須要在相應的結構體構造函數中加入super(ALIGN_NONE);設置對應的對齊方式。linux

unsigned類型處理

java中沒有對應的無符號類型,須要進行相應的轉換,以byte類型爲例(c中的 unsigned char)git

public class Util {
    public static byte sendUnsignedByte(int input){
        return (byte) (input & 0xFF);
    }

    public static int receiveUnsignedByte(byte input){
        return input & 0xFF;
    }
}

char*

const char* 做爲函數參數,能夠直接用字符串String傳值。github

char** 函數回傳字符串。用PointerByReference數組

char** 發送數據到struct的char**類型的字段中:new StringArray(String[] strings);jvm

獲取struct中的char**類型回傳的數據: String[] getStringArray(long offset, int length)函數

final PointerByReference ptrRef = new PointerByReference();
final Pointer p = ptrRef.getValue();
final String val = p.getString(0);

獲取數據,內存由c分配,那麼須要c同時提供jni接口釋放獲取到的內存。flex

發送數據:this

String strInfo = "very nice";
        byte[] bInfo = strInfo.getBytes();
        Memory info = new Memory(bInfo.length + 1);
        info.clear();
        info.write(0,bInfo,0,bInfo.length);
        info.setByte(bInfo.length,(byte)0);
        p.info = info;

struct 數組

獲取數據,要調用c的接口釋放分配的內存

傳遞數組到c:

關鍵方法:public Structure[] toArray(int size)用於在java中分配內存,和把c中獲取的內存空間轉化爲Structure數組.

callback

typedef void(*callback)(PERSON*);
public static class ShowCallBack implements Callback{
        public void invoke(Person.ByReference person){
            String name = "";
            byte[] data = person.name;
            int count = data.length;
            for(int i=data.length - 1;i>= 0;i--){
                if(data[i] != 0) {
                    break;
                }
                count--;
            }
            if(count > 0) {
                byte[] copy = new byte[count];
                System.arraycopy(data,0,copy,0,count);
                name = new String(copy);
            }
            System.out.println("callback name\t"+name);
        }
    }

用byte[]數組值給char[]

因爲c中字符串以\0結尾,所以須要在末尾多分配一個字節的空間,並把這個末尾字節設置爲0

byte[] bInfo = strInfo.getBytes();
        Memory info = new Memory(bInfo.length + 1);
        info.write(0,bInfo,0,bInfo.length);
        info.setByte(bInfo.length,(byte)0);

jvm異常退出

JNA也提供了一種保護機制。好比防止JNA出現異常不會致使JVM異常退出,默認是開啓這個功能的,開啓方式爲 System.setProperty("jna.protected","true"); 記得要在JNA加載庫文件以前調用,而後try {...} catch(Throwable e)異常,出現」非法內存訪問」的時候依然會致使jvm退出。

函數調用約定

_stdcall和_cdecl函數調用約定 參考連接

_cdecl,是C語言缺省的調用約定,參數採用從右到左的壓棧方式,函數自己不清理堆棧,調用者負責清理堆棧。對於這種庫,只要直接繼承Library。

_stdcall,是Pascal程序的缺省調用方式,WIN32 Api都採用_stdcall調用方式。參數採用從右到左的壓棧方式,被調函數自身在返回前清空堆棧。這種須要繼承StdCallLibrary。

若是用cpp實現庫,須要調用的函數申明添加extern "C"

#pragma  pack(push,1) //緊湊型對齊
#ifdef __cplusplus
extern "C" {
#endif
typedef void(*callback)(PERSON*);
void show(PERSON* person,const callback cb);
// ...更多的方法
#ifdef __cplusplus
}
#endif
#pragma pack(pop)

柔性數組成員(flexible array member)

struct blob {
    size_t length;
    unsigned char data[];
};
class Blob extends Structure {
    int length;
    byte[] data = new byte[1];
    public blob(int length) {
        this.length = length;
        this.data = new byte[length];
        allocateMemory();
    }
    public blob(Pointer p) {
        super(p);
        this.length = p.readInt(0);
        this.data = new byte[this.length];
        read();
    }
}

Strucure內存大小在java中有改動後須要及時調用allocateMemory()從新分配內存. write()方法把Strucure對象的改動及時寫入到本地內存中,read()從新把本地內存中的數據讀取到Strucure對象。

參考文件

官方文檔

用例文檔

相關文章
相關標籤/搜索