JNA java調用c/c++代碼

來源:互聯網
上載者:User

最近在搞一個小程式,需要用java調用DLL。用到的技術是JNA。

具體的內容在網上一搜都有,但是很多文章內容都差不多,而且都有些問題,也不知道是不是版本的問題,反正代碼拿來一copy各種問題,倒騰了好久,終於弄出點眉目出來,寫來與大家分享下。

首先,c/c++代碼如下:

extern "C" _declspec(dllexport) int add(int first, int second);

實現代碼:

int add(int first, int second) {printf("(c) test jna : %d + %d = %d\n", first, second, first + second);return first + second;}

封裝成DLL,copy到java工程的bin目錄下,

在java中使用時,首先需要匯入jna的包,過程網上都有,就不多說了,然後在代碼中需要添加:

import com.sun.jna.Library;import com.sun.jna.Native;import com.sun.jna.NativeLong;import com.sun.jna.Platform;import com.sun.jna.Pointer;import com.sun.jna.Structure;

調用代碼如下:

public class Dll {  public interface TestJnaLib extends Library  {  TestJnaLib INSTANCE = (TestJnaLib)Native.loadLibrary("DLL.dll", TestJnaLib.class);  int add(int first, int second);   }  public static void main(String[] args) {TestJnaLib.INSTANCE.add(23, 34);           }

好,第一個沒有任何問題,通過。

現在試試結構體:

給DLL 工程中添加這些(教程裡用的):

struct UserStruct{int id;char* name;int age;};extern "C" __declspec( dllexport )void sayUser(UserStruct* pUserStruct){printf("%ld %s %d\n",pUserStruct->id,pUserStruct->name,pUserStruct->age);}

按照教程的說法,封裝以及調用規則如下:

 public static class UserStruct extends Structure {            public int id;            public String name;            public int age;            public static class ByReference extends UserStructimplements Structure.ByReference { }            public static class ByValue extends UserStruct implements Structure.ByValue{ }@Overrideprotected List getFieldOrder() {List a = new ArrayList();        a.add("id");        a.add("name");        a.add("age");        return a;}        }

注意在教程裡沒有提到getFieldOrder這個函數,所以編譯會報錯,只好實現一下,查了一下,這個list返回的是封裝結構體中的變數名稱,這個一定不能寫反(不管是基本變數還是結構體變數,或者是數組什麼的,只需要添加名稱就可以)。

調用函式宣告:

 void sayUser(UserStruct.ByReference struct);

關於:

  public static class ByReference extends UserStructimplements Structure.ByReference { }  public static class ByValue extends UserStruct implements Structure.ByValue{ }

這兩個需要說一下,教程裡是說顯示的說明是值或引用,如果去掉也不影響,前提是定義變數的時候應該這樣寫:

TestJnaLib.UserStruct userStruct=new TestJnaLib.UserStruct();

我測試過了,這個寫對結果也沒有什麼影響,DLL調用成功,不過還是建議加上,這樣顯得更正確些。

測試代碼:

TestJnaLib.UserStruct.ByReference userStruct=new TestJnaLib.UserStruct.ByReference();  userStruct.id=100;  userStruct.age=30;  userStruct.name=new String("奧巴馬");  TestJnaLib.INSTANCE.sayUser(userStruct);

看聲明,是傳遞引用,所以顯示的使用了ByReference。

一定注意,在定義變數的時候使用的是UserStruct.ByReference ,因為函式宣告的是ByReference。前後一定要一致。

下面是問題最多的一塊:結構體數組:

定義如下:

struct CompanyStruct{int id;char* name;int count;UserStruct users[10];};extern "C" __declspec( dllexport )void sayCom(CompanyStruct* pCompanyStruct){printf("%ld %s %d\n",pCompanyStruct->id,pCompanyStruct->name,pCompanyStruct->count);for(int i=0;i<10;i++)printf("%ld %s %d\n",pCompanyStruct->users[i].id,pCompanyStruct->users[i].name,pCompanyStruct->users[i].age);} 

嵌套結構體:

教程裡是這樣封裝調用的:

public static class CompanyStruct extends Structure{public NativeLong id;public WString name;public UserStruct.ByValue[] users=newUserStruct.ByValue[100];public int count;}

但是會報錯(除了那個getFiledOrder函數外)。

回頭看看,可能是因為版本的問題吧,文章和教程都是08年的,現在JNA更新到了4.0了,可能對某些東西做了改動,所以會報錯。

嘗試著這樣定義:使用原始的方法定義:

  public static class CompanyStruct extends Structure{  public int id;  public String name;  public int count;  public UserStruct [] users=new UserStruct[10];  public static class ByReference extends CompanyStructimplements Structure.ByReference { }          public static class ByValue extends CompanyStruct implements Structure.ByValue{ }@Overrideprotected List getFieldOrder() {List a = new ArrayList();        a.add("id");        a.add("name");        a.add("count");        a.add("users");                return a;}  }

不用byValue了。如果這裡用到了byValue或者byReferfece都會報錯,即使編譯過了,運行也是錯的(其中有什麼invalid memory 訪問等一大堆各種奇葩的問題)。

想想,不管怎樣,在c模式下,數組其實跟指標是“相通”的。

函式宣告:

void sayCom(CompanyStruct.ByReference struct);

調用如下:

  TestJnaLib.CompanyStruct.ByReference companyStruct2=new TestJnaLib.CompanyStruct.ByReference();             companyStruct2.id=1000;  companyStruct2.name=new String("xueerfei");  companyStruct2.count=10;  TestJnaLib.UserStruct pUserStruct=new TestJnaLib.UserStruct();  pUserStruct.id=90;  pUserStruct.name=new String("xueerfei");  pUserStruct.age=99;  pUserStruct.write();      int offset = 0;  for(int i=0;i<companyStruct2.users.length;i++){  companyStruct2.users[i]=pUserStruct;  }   TestJnaLib.INSTANCE.sayCom(companyStruct2);

因為函數是Reference聲明,所以定義使用ByReference。(注意,如果在java裡函式宣告是一般聲明,那麼定義變數時也是用一般聲明,雖然在DLL中是指標參數,但是調用DLL經測試是成功的,這點我很納悶,可能在轉換的時候java已經自動識別了吧,保險一下,還是顯示的使用聲明吧)

注意這裡:

TestJnaLib.UserStruct pUserStruct=new TestJnaLib.UserStruct();

不用顯示的使用Reference,因為在定義的時候使用的是普通的new,所以這裡也而且必須使用普通的變數定義。

這樣調用就成功了。

其他的說明教程裡都有講的比較詳細,就不多說了。

因為技術也在發展,所以教程裡的某些東西可能因為更新而被修改,所以閱讀的時候還需要自己再實際的測試使用才行。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.