JNA 傳參char[] 和結構體等


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

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

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

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

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

  3、電腦缺少dll依賴的組件(例如我重裝完系統怎么調用都不成功,最后發現缺少了Visual C++ Redistributable Packages for Visual Studio 2013這個組件 下載地址,也有可能是其他組件可以用VS的插件查看,具體請百度)

三、java-c 數據類型映射   jna操作文檔 下載地址

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

1、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()//會導致亂碼

2、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);

3、傳參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);

4、傳參結構體    可以參考  原文地址

//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()方法會把結構體的所有字段固定住,使原生函數可以訪問。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM