java呼叫C/C++生成的dll動態連結庫----藉助JNI
由於專案的需要,最近研究了java 呼叫DLL的方法,將如何呼叫的寫於此,便於日後查閱:
採用的方法是JNI:Java Native Interface,簡稱JNI,是Java平臺的一部分,可用於讓Java和其他語言編寫的程式碼進行互動。
下面是從網上摘取的JNI工作示意圖:
總體說明:先在JAVA中建立一個類,通過javac生成.class,再由javah生成.h;然後將.h複製到VC下,由VC實現具體函,
並編譯通過後生成DLL,將DLL放入JAVA工程中使用,完畢。
下面說說具體步驟(含例項):
1、建java類:裝載DLL,宣告要使用DLL方法,具體實現由DLL負責;程式碼如下:
public class Java2cpp
{
static
{
System.loadLibrary("javaCallcpp");
}
public native int DLL_ADD(int a,int b); //加
public native int DLL_SUB(int a,int b); //減
public native int DLL_MUL(int a,int b); //乘
public native int DLL_DIV(int a,int b); //除
public static void main(String args[])
{
int sum = 0;
Java2cpp test = new Java2cpp();
sum = test.DLL_ADD(2, 4);
System.out.println("Java call cpp dll result:" + sum);
}
}
2、生成.h檔案:cmd 到Java2cpp.java目錄下,做如下操作:
第一步:javac -encoding UTF-8 Java2cpp.java 生成java2cpp.class
第二步:javah Java2cpp 生成Java2cpp.h標頭檔案,內容如下:
注意3、製做VC動態庫:建立一個C/C++動態庫工程,命名為javaCallcpp,匯入java2cpp.h並實現其方法:
#include "Java2cpp.h"
#include "dllApi.h"
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1ADD(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_ADD(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1SUB(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_SUB(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1MUL(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_MUL(a,b);
return var;
}
JNIEXPORT jint JNICALL Java_Java2cpp_DLL_1DIV(JNIEnv *env, jobject obj, jint a, jint b)
{
int var = 0;
var = DLL_API_DIV(a,b);
return var;
} //此檔案完
加DLL_API_ADD()、減DLL_API_SUB()、乘DLL_API_MUL()、除DLL_API_DIV()四個函式在別一個
檔案中實現,檔名是dllApi.cpp,實現如下:
int DLL_API_ADD(int a,int b)
{
return (a+b);
}
int DLL_API_SUB(int a,int b)
{
return (a-b);
}
int DLL_API_MUL(int a,int b)
{
return (a*b);
}
int DLL_API_DIV(int a,int b)
{
return (a/b);
} //此檔案完
此時工程還編譯不過,因為include<jni.h>出錯,需新增JNI所在的目錄,如下:
4、編譯動態庫工程:生成javaCallcpp.dll,並將這個動態庫複製到java工程目錄下:
5、使用DLL:執行java程式,結果如下:
至此,java呼叫dll已經完成。 *****************************************************分割線************************************************************************* 如果dll傳來的有中文情況,可能會出現亂碼。 解決策略為(在自己的專案中第二個方法即jstring WindowsTojstring(JNIEnv* env, const char* str) 是可以用的): #include "getChinese.h" #include "testDLL_Java2cpp.h" #include <Windows.h> char* jstringToWindows(JNIEnv *env, jstring jstr); jstring WindowsTojstring(JNIEnv* env, const char* str); JNIEXPORT jstring JNICALL Java_testDLL_Java2cpp_getResult (JNIEnv *env, jobject obj, jstring name) { string str = "hello 你好啊,這是一個測試的dll"; const char* result = str.c_str(); jstring js = WindowsTojstring(env,result); return js; /* if ( r!= NULL){ return env->NewStringUTF(r); cout << r << endl; } else{ //return NULL; return env->NewStringUTF(result); }*/ } char* jstringToWindows(JNIEnv *env, jstring jstr) { //UTF8/16轉換成gb2312 int length = (env)->GetStringLength(jstr); const jchar* jcstr = (env)->GetStringChars(jstr, 0); int clen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, NULL, 0, NULL, NULL); char* rtn = (char*)malloc(clen); //更正。作者原來用的是(char*)malloc( length*2+1 ),當java字串中同時包含漢字和英文字母時,所需緩衝區大小並不是 2倍關係。 int size = 0; size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, rtn, clen, NULL, NULL); if (size <= 0) return NULL; (env)->ReleaseStringChars(jstr, jcstr); rtn[size] = 0; return rtn; } jstring WindowsTojstring(JNIEnv* env, const char* str) {//gb2312轉換成utf8/16 jstring rtn = 0; int slen = strlen(str); unsigned short * buffer = 0; if (slen == 0) rtn = (env)->NewStringUTF(str); else { int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0); buffer = (unsigned short *)malloc(length * 2 + 1); if (MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length) >0) rtn = (env)->NewString((jchar*)buffer, length); } if (buffer) free(buffer); return rtn; } 不管將c++的程式碼檔案如何設定為utf-8 還是會出現中文亂碼,所以採用上述的編碼方式可以解決這個問題。 *****************************************************貼出java側的輸出結果*********************************** package testDLL; public class Java2cpp { static { System. loadLibrary("callDLL"); } public native String getResult(String in); public static void main(String[] args) { // TODO Auto-generated method stub String result = ""; Java2cpp test = new Java2cpp(); result = test.getResult( "李海濤");//這裡的輸入有點多餘了 System. out.println( result); } }