程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> JINI(1) Java與C/C++的交互

JINI(1) Java與C/C++的交互

編輯:C++入門知識

用JINI來實現Java與C/C++的相互調用.感覺好麻煩,但形勢就這樣,沒辦法。

環境:Win7+VS2012+Java 1.7

1. 編寫一個Java文件,對於需要C/C++實現的方法,聲明為native(本地方法)

裡面有個System.loadLibrary即從java.library.path中指定的目錄下面加載指定的動態鏈接庫,無須指定目錄和擴展名,直接在參數中輸入庫名稱即可。

也可以用System.load直接指定路徑的方式來加載。效果是一樣的。

package com.xcl.jini;

public class XclJini {

	    //聲明為本地方法,生成為C/C++使用的.h 頭文件中的函數聲明。
	    public native int GetVersion();	    
	    public native int GetStatus();
	    public native String GetMsg();
	    public native int SendMsg(String msg);
		
		static {
			//jvm變量
			//System.out.println(System.getProperty("java.library.path"));
			//C:\java\jdk\bin
			System.loadLibrary("XclJiniLib");			
			//System.load("C:\\java\\jdk\\bin\\XclJiniLib.dll");
		}
		
	/**
	 * @param args
	 */
	public static void main(String[] args){
		System.out.println("__________________________"); 
		System.out.println("Java: jini 演示!");	
		
		XclJini _XclJini = new XclJini();		
		_XclJini.GetVersion();
		_XclJini.GetStatus();
		_XclJini.SendMsg("發個信息給C++.");
		String msg = _XclJini.GetMsg();
		System.out.println("java:"+msg);		
		System.out.println("__________________________"); 
	}
}

2. 首先通過javac編譯成class,再通過javah生成供C/C++使用的.h頭文件。

因為XclJini.java中包含中文件,且是用utf-8格式存儲的,所以編譯時javac要加上 -encoding utf-8 參數,否則中文會顯示成亂碼。

另javah時,要注意,其路徑中src下,然後javah後接類路徑才能生成正確的頭文件

D:\AppWork\XExample\workspace\jni_demo1\src>javac -encoding utf-8 com/xcl/jini/XclJini.java

D:\AppWork\XExample\workspace\jni_demo1\src>javah com.xcl.jini.XclJini

D:\AppWork\XExample\workspace\jni_demo1\src>dir D:\AppWork\XExample\workspace\jni_demo1\src\com\xcl\jini\*.*
 驅動器 D 中的卷是 Data
 卷的序列號是 0EC2-012C

 D:\AppWork\XExample\workspace\jni_demo1\src\com\xcl\jini 的目錄

2014/03/24  17:04              .
2014/03/24  17:04              ..
2014/03/24  23:15               804 XclJini.class
2014/03/24  23:14               683 XclJini.java
               2 個文件          1,487 字節
               2 個目錄 19,575,050,240 可用字節

D:\AppWork\XExample\workspace\jni_demo1\src>dir
 驅動器 D 中的卷是 Data
 卷的序列號是 0EC2-012C

 D:\AppWork\XExample\workspace\jni_demo1\src 的目錄

2014/03/24  23:16              .
2014/03/24  23:16              ..
2014/03/23  23:20              com
2014/03/24  23:16             1,046 com_xcl_jini_XclJini.h
               1 個文件          1,046 字節
               3 個目錄 19,575,050,240 可用字節

D:\AppWork\XExample\workspace\jni_demo1\src>

3. C/C++對其頭文件的實現.

#include "com_xcl_jini_XclJini.h"

#include 
#include "ConvertJini.h"

/*
 * Class:     com_xcl_jini_XclJini
 * Method:    GetVersion
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_xcl_jini_XclJini_GetVersion
  (JNIEnv *, jobject)
{

	printf("C++: GetVersion() Version 1.1\n");
	return 0;
}

/*
 * Class:     com_xcl_jini_XclJini
 * Method:    GetStatus
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_xcl_jini_XclJini_GetStatus
  (JNIEnv *, jobject)
{
	printf("C++: GetStatus()\n");
	printf("C++: Running.....\n");
	printf("C++: GetStatus() end.\n");
	return 1;
}

/*
 * Class:     com_xcl_jini_XclJini
 * Method:    GetMsg
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_xcl_jini_XclJini_GetMsg
  (JNIEnv * env, jobject jobj)
{
	printf("C++: GetMsg()\n");
	char *ret = "C++ Message.";
	ConvertJini cj ;
	jstring jret = cj.stoJstring(env,ret);

	printf("C++: GetMsg() end.\n");
	return jret;
	
}

/*
 * Class:     com_xcl_jini_XclJini
 * Method:    SendMsg
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_xcl_jini_XclJini_SendMsg
  (JNIEnv * env, jobject jobj, jstring msg)
{
	printf("C++: SendMsg()\n");
	
	jboolean  b  = true;
    char s[80];	
    memset(s, 0, sizeof(s));
    strcpy_s(s ,(char*)env->GetStringUTFChars(msg, &b));
    printf("C++: Java Message:%s\n", s);
    env->ReleaseStringUTFChars(msg , NULL);

	printf("C++: SendMsg() end.\n");
	return 0;
}

要注意的地方之一是,GetStringUTFChars後,要記得用ReleaseStringUTFChars來釋放空間,否則會造成內存洩漏。


char*與jstring的相互轉換行數,這個感覺好麻煩.

//jstring to char*
char* ConvertJini::jstringTostring(JNIEnv* env, jstring jstr)
{        
	errno_t err;
	char* rtn = NULL;
	jclass clsstring = env->FindClass("java/lang/String");
	jstring strencode = env->NewStringUTF("utf-8");
	jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
	jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
	jsize alen = env->GetArrayLength(barr);
	jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
	if (alen > 0)
	{
		rtn = (char*)malloc(alen + 1);

		err = memcpy_s(rtn,alen + 1, ba, alen);
		rtn[alen] = 0;
	}
	env->ReleaseByteArrayElements(barr, ba, 0);
	return rtn;
}

//char* to jstring
jstring ConvertJini::stoJstring(JNIEnv* env, const char* pat)
{
	size_t maxlen = 500;

	jclass strClass = env->FindClass("Ljava/lang/String;");
	jmethodID ctorID = env->GetMethodID(strClass, "", "([BLjava/lang/String;)V");
	jbyteArray bytes = env->NewByteArray(strnlen(pat,maxlen));
	env->SetByteArrayRegion(bytes, 0, strnlen(pat,maxlen), (jbyte*)pat);
	jstring encoding = env->NewStringUTF("utf-8");
	return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
} 


def文件:

LIBRARY	"XclJiniLib"
EXPORTS
Java_com_xcl_jini_XclJini_GetVersion    @1 


C/C++需要從JDK中引入頭文件jini.h,才能做編譯。

C:\java\jdk\include;C:\java\jdk\include\win32

4. 編譯出dll文件,將其用load或loadLibrary來加載C++動態庫。

例子中,我將其復制到了C:\java\jdk\bin 下。

編譯時要注意是32位還是64位,如位數不對,Java加載時會報下面的錯:

Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\java\jdk\bin\XclJiniLib.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
	at java.lang.ClassLoader$NativeLibrary.load(Native Method)
	at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1939)
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1864)
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1854)
	at java.lang.Runtime.loadLibrary0(Runtime.java:845)
	at java.lang.System.loadLibrary(System.java:1084)
	at com.xcl.jini.XclJini.(XclJini.java:14)


5. 運行結果如下.

__________________________
Java: jini 演示!
java:C++ Message.
__________________________
C++: GetVersion() Version 1.1
C++: GetStatus()
C++: Running.....
C++: GetStatus() end.
C++: SendMsg()
C++: Java Message:發個信息給C++.
C++: SendMsg() end.
C++: GetMsg()
C++: GetMsg() end.
發現Java的都顯示中前面,C/C++的printf輸出的都顯示中後面。

在C/C++中接由到Java的jstring 時,如果包含漢字,可加上字符轉換函數,來將其轉為正確的字符集,否則有可能會顯示亂碼。

MAIL: [email protected]

BLOG: http://blog.csdn.net/xcl168


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved