JNA 傳參char[] 和結構體等

近日項目中須要用java調用c/c++編寫的dll庫,全部瞭解到jna這個東東,下面是使用的一些經驗:java

1、java使用Jna須要兩個jar包,eg:jna-3.5.1.jar和platform-3.5.1.jar 下載地址,添加完依賴包後把需調用的dll放到項目根目錄下就是和src同級目錄下c++

2、報錯:Unable to load DLL 'xxx.dll': 找不到指定的模塊,可能有一下幾個問題:數組

     一、使用的jdk和dll位數不一樣,64位的jdk只能調用64位的dll,32同樣。函數

     二、dll的位置放的不對(也有說放在c盤的systen32下的)測試

  三、電腦缺乏dll依賴的組件(例如我重裝完系統怎麼調用都不成功,最後發現缺乏了Visual C++ Redistributable Packages for Visual Studio 2013這個組件 下載地址,也有多是其餘組件能夠用VS的插件查看,具體請百度)編碼

3、java-c 數據類型映射   jna操做文檔 下載地址spa

常見的映射就不說了,這裏說一下我項目中用到的:.net

一、char*&插件

//dll中
int pack_clou102(char*& sendstr)

//java中接口    PointerByReference 表示指針的引用類型
public int pack_clou102(PointerByReference send);

//獲取send      
String str = send.getValue().getString(0);
//send.getValue()獲取的是一個指針   而getString(0)是獲取指針的值   這裏不能夠用
 send.getValue().toString()//會致使亂碼

二、char*指針

//根據dll的操做來決定,官方char*對應String

//可是下面這個例子中用byte[]才能夠

//dll中
//UINT8是指無符號8位二進制整型  在這裏映射String會出現編碼問題的,因此這裏用byte[]
int unpack_clou102(char* recvbuf)
{
	UINT8* pbuf = (UINT8*)recvbuf;   
	UINT8 ucCheckSum = 0;// 校驗和

。。。
}

//java中
 public int unpack_clou102(byte[] recvbuf);

三、傳參char[]

//dll
int pack_clou102(char[20] send){
。。。
return 0;
}
//有時候會遇到dll中用char[]傳字符串的,java中是用byte[],這時候能夠借用「」.getbytes()
//jna
byte[20] bytes = "2016-08-29 11:06:23".getbytes();
int mun = pack_clou102(bytes);

四、傳參結構體    能夠參考  原文地址

//DLL中
struct
CompanyStruct{ long id; wchar_t* name; UserStruct* users[100]; int count; };
//java中
public
static class CompanyStruct2 extends Structure{   public NativeLong id;   public WString name;   public UserStruct.ByReference[] users=new UserStruct.ByReference[100];   public int count; }
//測試代碼
CompanyStruct2.ByReference companyStruct2=new CompanyStruct2.ByReference(); companyStruct2.id=new NativeLong(2); companyStruct2.name=new WString("Yahoo"); companyStruct2.count=10; UserStruct.ByReference pUserStruct=new UserStruct.ByReference(); pUserStruct.id=new NativeLong(90); pUserStruct.age=99; pUserStruct.name=new WString("楊致遠"); // pUserStruct.write(); for(int i=0;i<companyStruct2.count;i++){ companyStruct2.users[i]=pUserStruct; } TestDll1.INSTANCE.sayCompany2(companyStruct2);

 

執行測試代碼,報錯了。這是怎麼回事?考察JNI 技術,咱們發現Java 調用原生函數時,會把傳遞給原生函數的Java 數據固定在內存中,這樣原生函數才能夠訪問這些Java 數據。對於沒有固定住的Java 對象,GC 能夠刪除它,也能夠移動它在內存中的位置,以使堆上的內存連續。若是原生函數訪問沒有被固定住的Java 對象,就會致使調用失敗。固定住哪些java 對象,是JVM 根據原生函數調用自動判斷的。而上面的CompanyStruct2結構體中的一個字段是UserStruct 對象指針的數組,所以,JVM 在執行時只是固定住了CompanyStruct2 對象的內存,而沒有固定住users 字段引用的UserStruct 數組。所以,形成了錯誤。咱們須要把users 字段引用的UserStruct 數組的全部成員也所有固定住,禁止GC 移動或者刪除。若是咱們執行了pUserStruct.write();這段代碼,那麼就能夠成功執行上述代碼。Structure 類的write()方法會把結構體的全部字段固定住,使原生函數能夠訪問。

相關文章
相關標籤/搜索