要注意調用的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
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; } }
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;
獲取數據,要調用c的接口釋放分配的內存
傳遞數組到c:
關鍵方法:public Structure[] toArray(int size)
用於在java中分配內存,和把c中獲取的內存空間轉化爲Structure
數組.
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); } }
因爲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);
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)
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
對象。