近日項目中須要用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()方法會把結構體的全部字段固定住,使原生函數能夠訪問。