JNA java呼叫c/c++程式碼
最近在搞一個小程式,需要用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);
}
按照教程的說法,封裝以及呼叫規則如下:
注意在教程裡沒有提到getFieldOrder這個函式,所以編譯會報錯,只好實現一下,查了一下,這個list返回的是封裝結構體中的變數名稱,這個一定不能寫反(不管是基本變數還是結構體變數,或者是陣列什麼的,只需要新增名稱就可以)。public static class UserStruct extends Structure { public int id; public String name; public int age; public static class ByReference extends UserStruct implements Structure.ByReference { } public static class ByValue extends UserStruct implements Structure.ByValue{ } @Override protected List getFieldOrder() { List a = new ArrayList(); a.add("id"); a.add("name"); a.add("age"); return a; } }
呼叫函式宣告:
void sayUser(UserStruct.ByReference struct);
關於:
public static class ByReference extends UserStruct implements 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=new
UserStruct.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 CompanyStruct implements Structure.ByReference { }
public static class ByValue extends CompanyStruct implements Structure.ByValue{ }
@Override
protected 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,所以這裡也而且必須使用普通的變數定義。
這樣呼叫就成功了。
其他的說明教程裡都有講的比較詳細,就不多說了。
因為技術也在發展,所以教程裡的某些東西可能因為更新而被修改,所以閱讀的時候還需要自己再實際的測試使用才行。
相關推薦
JNA java呼叫c/c++程式碼
最近在搞一個小程式,需要用java呼叫DLL。用到的技術是JNA。 具體的內容在網上一搜都有,但是很多帖子內容都差不多,而且都有些問題,也不知道是不是版本的問題,反正程式碼拿來一copy各種問題,倒騰了好久,終於弄出點眉目出來,寫來與大家分享下。 首先,c/c++程式碼如
JNA(JAVA呼叫lib/so)
JNA用途 當需要java直接呼叫c編寫的dll或者so時候就可以用到JNA 當然也可以用JNI也是可以的JNA相對JNI的優勢是 JNA是在JAVA中把JAVA的資料轉換成C的資料。 也就是開發量在JAVA端。JNI是需要修改C程式碼。 用法 直接吧JNA.ja
JNA—java呼叫dll最簡單的方法
介紹給大家介紹一個最新的訪問本機程式碼的Java框架—JNA。JNA(Java Native Access)框架是一個開源的Java框架,是SUN公司主導開發的,建立在經典的JNI的基礎之上的一個框架。 JNA例子 例子1 現在讓我們執行一個JNA程式,感受它的
(四)NDK開發之 java 與C/C++ 程式碼互相呼叫
java 呼叫c/c++ 的方法,很簡單。我們勾選建立支援C/C++ 專案的時候,就已經生成了一個Demo 下面主要介紹,C/C++ 呼叫 java 的方法。 一、訪問 java 成員非靜態成員變數: JNI 呼叫java非靜態變數的 方法名格式 : Ge
JNI 最簡單的Java呼叫C/C 程式碼
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
java呼叫C++程式碼
首先我的參考部落格如下: 流程如下: 1.建立一個java檔案 public class ForDll { static { System.loadLibrary("javaCallcpp"); } public native int my
Android開發中在JAVA中呼叫C/C++ native程式碼
Android 從Java呼叫C/C++ 當無法用 Java 語言編寫整個應用程式時,JNI 允許您呼叫C/C++本機程式碼。在下列典型情況下,您可能決定使用本機程式碼: 希望用更低階、更快的程式語言C/C++去實現對時間有嚴格要求的程式碼。
Java 呼叫 C/C++ 之 JNA 系列實戰篇 —— 輸出char * (六)
一、 工作環境 1. windows (64位), JDK (64位),dll檔案 (64位) 2. Linux (64位), JDK (64位),so檔案 (64位) 二、 實際操作 1.在cf.h
Android NDK(JNI)學習總結一:Java程式碼中申明native函式-Java呼叫C函式,並在C函式中訪問java類和方法、屬性
本文不涉及android-ndk開發環境搭。 步驟一:新建一個APP,名稱為HelloJNI,然後定義一個類(將會在native程式碼中呼叫和訪問該類): package com.example.hellojni; public class JNITe
從 C/C++ 程式呼叫 Java 程式碼
JNI允許您從本機程式碼內呼叫 Java 類方法。 要做到這一點,通常必須使用 Invocation API 在本機程式碼內建立和初始化一個 JVM。 下列是您可能決定從 C/C++ 程式碼呼叫Java 程式碼的典型情況: 1.希望實現的這部分程式碼是平臺無關的,它
安卓使用記錄筆記(1)ndk使用之Java呼叫c++程式碼
1.在Java中新建一個Utils類 1)指定路徑下新建一個資料夾 ,包名為Utils 2) 新建類 NativeUtils.java package com.sample.Utils; publi
Java 呼叫 C/C++ 之 JNA 系列實戰篇 —— 輸入wchar_t* (二)
一、 工作環境 1. windows (64位), JDK (64位),dll檔案 (64位) 2. Linux (64位), JDK (64位),so檔案 (64位) 3. 二、 實際操作
JNI java呼叫c程式碼 (一)靜態註冊
今天說的程式碼是從java層呼叫c程式碼,然後再反調java程式碼的。這裡在java用的是靜態註冊,也就是jni方法名是根據java的檔案路徑生成的,不是動態註冊。 一、java呼叫jni,靜態註冊 先看:java註冊jni,以及呼叫jni函式: package com.
chromium JNI呼叫之java呼叫c++程式碼
這篇blog我們主要來介紹下chromium下content目錄下的jni呼叫. JNI呼叫主要分兩塊: 1. Java調cpp(cc) 2. Cc(cpp)調Java 現在,我們這裡介紹Java調cc. 要實現java呼叫cc檔案,要準備三個檔案:cc檔案
Java(JNA)調用C++動態庫(dll)
x86 class hid enc spa 好的 開源 技術分享 lan JNA(Java Native Access):是建立在JNI之上的Java開源框架,SUN主導開發,用來調用C、C++代碼,尤其是底層的庫文件(windows中叫dll文件,linux下是.so文件
CRC32 C語言程式碼 和 JAVA程式碼
C語言如下: uint32_t crc32_compute(uint8_t const * p_data, uint32_t size){ uint32_t crc; crc = 0xFFFFFFFF; for (uin
CRC8 C語言程式碼 和 JAVA 程式碼
crc8 從語言程式碼如下: unsigned char const crc8_tab[256] = { 0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x
Eclipse直接完成JAVA呼叫C/C++ (Eclipse上使用CDT結合MinGW)
原文地址:http://www.blogjava.net/orangewhy/archive/2007/05/24/119645.html 網上都有很多在windows平臺下JAVA呼叫C/C++方法的介紹說明。但是,在此過程中
JNI之 c/c++呼叫java建構函式
有時候c/c++是面向過程編碼,很多有用工具類都沒有,要編碼人員自己實現,如果可以呼叫java大量存在的類豈不是更省事更簡潔。 下面是通過呼叫java的Date類產生是時間戳。 public class JniConsTest { //c訪問java建構函式,並返回物件
JNI 之c/c++和Java互動,呼叫java成員
public class JniTest2 { //c訪問非靜態成員 public String testField="hello..."; //c修改java靜態成員 public static int time=78; //c訪問java 方