Java:Create .DLL file in VC++ for JNI
這篇將指引該如何從Java開始,到利用Visual C++ 2005,建立JNI使用的DLL動態連結函式庫。
首先,要先寫好一個使用JNI的Java程式,這裡以JniExample.java作為範例,程式碼如下。
1. 由java撰寫開始
接著我們編譯這個Java程式,但是不要急著執行,行也只會得到錯誤訊息。
錯誤訊息是說,在指定的java.library.path中,找不 到指定的MyDLL.dll[註1],這個dll的名稱是在JavaClassWithNativeMethod類別的static initializer block(靜態初始化區塊),以 System.loadLibrary所指定的。
2. 取得相應類別的JNI標頭檔
利用JDK中的javah建立JNI的C/C++的標頭檔(header)
注意,使用javah是針對擁有Native方法的類別,也就是JavaClassWithNativeMethod。若是針對主程式JniExample,只會得到一個JNI的空殼標頭,沒有意義。
得到的標頭檔,檔名應該是JavaClassWithNativeMethod.h,如有不同請自行替換。
3. VC++2005的設定
接著就可以開啟我們的VC++ 2005的環境,於工具列點選「檔案(F)」→「新增(N)」→「專案(P)」開啟專案精靈。將'專案類型'選取Visual C++中的「Win32」,'範本'使用「Win32專案」,名稱取為MyDLL[註2]後按下確定,如上圖所示。
之後還會出現Win32應用程式精靈,請將'應用程式類型'選取為DLL,其他選項為空專案[註3]。
接著將javah所得到的標頭檔,丟到你的VC++專案資料夾中,然後對著VC++方案總管的「標頭檔」資料夾按下右鍵,「加入」→「現有項目」,將標頭檔選近來。
再對原始程式檔按右鍵,「加入」→「新增項目」,點選'分類'的程式碼,範本用'C++檔(.cpp)',然後取名為main。
接著將JNI標頭引入,並輸入原生的程式碼,這裡以下面的C++程式碼作為範例。
最後我們要設定專案的屬性,將JNI其他的相關標頭檔加入專案。
在'組態屬性'中C/C++的一般,在列表中的'其他 Include 目錄'中加入{JDK目錄}\include,以及{JDK目錄}\include\win32。我的電腦中的JDK目錄是在H:\Program Files\Java\jdk1.6.0_03\,所以後的結果,最後如圖所示。
設定完成後,就可以按下F7建置專案,就會在專案目錄的DEBUG底下找到MyDLL.dll。
4. 執行具有JNI的Java程式
將MyDLL.dll與JniExample的類別放置在一起,直接執行java JniExample,就能看到程式結果。
或是你可以直接將JniExample.class放置在專案中,用這個指令執行
本篇內文所使用之程式碼,由JDK 6 update 3與Visual C++2005 sp1合作,編譯並執行成功。
[註1] 以Windows上來說是dll,而Linux則是so,但是本篇是指導VC++的設定,因此不需要理會Linux平台的動態連結函式庫。
[註2] 取名為MyDLL是為了編譯後得到MyDLL.dll,否則編譯出來了dll檔需要再改名。
[註3] 空專案只是希望不要被VC自動產生程式碼給搞亂了,實際上可以自由選擇。
首先,要先寫好一個使用JNI的Java程式,這裡以JniExample.java作為範例,程式碼如下。
1. 由java撰寫開始
public class JniExample {
// 主程式
public static void main(String[] args) {
JavaClassWithNativeMethod j =
new JavaClassWithNativeMethod(
);
String[] strs = new String[]{"apple","banana","class"};
// 呼叫原生方法
boolean b = j.useNativeMethod(strs);
if (b == true)
System.out.println("Java:All ok, return true.");
else
System.out.println("Java:Somthing wrong, return false.");
}
}
class JavaClassWithNativeMethod {
// 載入所使用的DLL檔案
static {
System.loadLibrary("MyDLL");
System.out.println("Java:Loading dll is compelete.");
}
public JavaClassWithNativeMethod() {
System.out.println("Java:A new instance created");
}
// 使用JNI的Method,具有native修飾子並且Method為空
public native boolean useNativeMethod(String[] println);
}
接著我們編譯這個Java程式,但是不要急著執行,行也只會得到錯誤訊息。
Exception in thread "main" java.lang.UnsatisfiedLinkError: no MyDLL in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at JavaClassWithNativeMethod.(JniExample.java:17)
at JniExample.main(JniExample.java:4)
利用JDK中的javah建立JNI的C/C++的標頭檔(header)
javah JavaClassWithNativeMethod
注意,使用javah是針對擁有Native方法的類別,也就
得到的標頭檔,檔名應該是JavaClassWithNativeMethod.h,如有不同請自行替換。
接著就可以開啟我們的VC++ 2005的環境,於工具列點選「檔案(F)」→「新增(N)」→「專案(P)」開啟專案精靈。
再對原始程式檔按右鍵,「加入」→「新增項目」,點選'分類'的程式碼,範本用'C++檔(.cpp)',然後取名為main。
接著將JNI標頭引入,並輸入原生的程式碼,這裡以下面的C++程式碼作為範例。
#include <iostream>
#include <windows.h>
#include "JavaClassWithNativeMethod.h"
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
return TRUE;
}
JNIEXPORT jboolean JNICALL
Java_JavaClassWithNativeMethod_useNativeMethod
(JNIEnv * env, jobject obj, jobjectArray par1)
{
cout<<"Native:I'm working."<<endl;
for (jint i=0 ; i<env->GetArrayLength(par1) ; i++) {
// 由於Java的String是物件,不是primitive type
// 所以取得陣列中的元素,是使用GetObjectArrayElement函式
jstring javaStr =
(jstring)env->GetObjectArrayElement(par1 ,i);
wchar_t* wchStr = (wchar_t*)env->GetStringChars(javaStr, NULL);
jsize wchStrlen = env->GetStringLength(javaStr);
// Win32 API的訊息對話框
MessageBox(NULL,wchStr,L"訊息視窗",MB_OK);
}
cout<<"Native:It is easy to show those Strings."<<endl;
return false;
}
最後我們要設定專案的屬性,將JNI其他的相關標頭檔加入專案。
4. 執行具有JNI的Java程式
將MyDLL.dll與JniExample的類別放置在一起,直接執行java JniExample,就能看到程式結果。
或是你可以直接將JniExample.class放置在專案中,用這個指令執行
java -cp . -Djava.library.path=.\Debug JniExample
本篇內文所使用之程式碼,由JDK 6 update 3與Visual C++2005 sp1合作,編譯並執行成功。
[註1] 以Windows上來說是dll,而Linux則是so,但是本篇是指導VC++的設定,因此不需要理會Linux平台的動態連結函式庫。
[註2] 取名為MyDLL是為了編譯後得到MyDLL.dll,否則編譯出來了dll檔需要再改名。
[註3] 空專案只是希望不要被VC自動產生程式碼給搞亂了,實際上可以自由選擇。
留言