1. 程式人生 > >JNA java呼叫c/c++程式碼

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);
}

按照教程的說法,封裝以及呼叫規則如下:
 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;
				}
	        }
注意在教程裡沒有提到getFieldOrder這個函式,所以編譯會報錯,只好實現一下,查了一下,這個list返回的是封裝結構體中的變數名稱,這個一定不能寫反(不管是基本變數還是結構體變數,或者是陣列什麼的,只需要新增名稱就可以)。

呼叫函式宣告:

 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

JNAjava呼叫dll最簡單的方法

介紹給大家介紹一個最新的訪問本機程式碼的Java框架—JNA。JNA(Java Native Access)框架是一個開源的Java框架,是SUN公司主導開發的,建立在經典的JNI的基礎之上的一個框架。 JNA例子 例子1    現在讓我們執行一個JNA程式,感受它的

(四)NDK開發之 javaC/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檔案

JavaJNA)調用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 方