Java:Create .DLL file in VC++ for JNI

這篇將指引該如何從Java開始,到利用Visual C++ 2005,建立JNI使用的DLL動態連結函式庫。

首先,要先寫好一個使用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)
錯誤訊息是說,在指定的java.library.path中,找不到指定的MyDLL.dll[註1],這個dll的名稱是在JavaClassWithNativeMethod類別的static initializer block(靜態初始化區塊),以System.loadLibrary所指定的。

2. 取得相應類別的JNI標頭檔

利用JDK中的javah建立JNI的C/C++的標頭檔(header)


javah JavaClassWithNativeMethod


注意,使用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++程式碼作為範例。

#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其他的相關標頭檔加入專案。

在'組態屬性'中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放置在專案中,用這個指令執行

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自動產生程式碼給搞亂了,實際上可以自由選擇。

留言