320 likes | 520 Views
JNI (Java Native Interface). 呼叫 C ++ 的 function 井民全. Outline. Java 呼叫 C++ function 6 Steps 製作流程 參數的傳遞 傳入一個字串 如何傳遞陣列物件並且改值. 製作流程 with 6 Steps. 建立 java class 包含 native methods 產生 class file 產生 . h 檔 給 C++ 用 在 C++ 撰寫 native methods 的 實作 產生 dll 執行 java 程式, 動態呼叫.
E N D
JNI (Java Native Interface) 呼叫 C ++ 的 function 井民全
Outline • Java 呼叫 C++ function • 6 Steps 製作流程 • 參數的傳遞 • 傳入一個字串 • 如何傳遞陣列物件並且改值
製作流程 with 6 Steps • 建立 java class • 包含 native methods • 產生 class file • 產生 .h檔 給C++用 • 在C++撰寫native methods的實作 • 產生 dll • 執行java程式,動態呼叫
建立 java class 1/2 public class JNIDemo{ } // 1. 宣告一個 native method public native void displayHelloWorld(); // 2. 載入 C++ 實作的 dll library static { System.loadLibrary(“JNIC_plusImplement”); }
建立 java class 1/2 public class JNIDemo{ // 1. 宣告一個 native method public native void displayHelloWorld(); // 2. 載入 C++ 實作的 dll library static { System.loadLibrary(“JNIC_plusImplement”); } } // 測試程式: 呼叫 native method public static void main(String args[]){ new JNIDemo().displayHelloWorld(); }
1. 指向 JNIDemo.java 產生.h 檔 1/2 2. 滑鼠右鍵: 選擇 Properties
1. 選擇 Build tab 2. 選擇 Build tab 3. 將可以產生 JNIDemo_JNIDemo.h 產生.h 檔 2/2
撰寫native methods • 建立一個空的 DLL project
撰寫native methods 2. 新增加一個 C++ Source file
// 一定要加入的 include檔 // 前面產生的 include檔 傳遞參數用 相當this 物件 撰寫native methods #include <jni.h> #include "JNIDemo_JNIDemo.h" #include <stdio.h> JNIEXPORT void JNICALL Java_JNIDemo_JNIDemo_displayHelloWorld(JNIEnv *env, jobject obj) { printf("Hello world!\n"); return; }
1. 選擇 C/C++ tab 2. 選擇 Preprocessor類別 3. 把 Jni.h與 相關 .h 的路徑 設定好 注意事項: include path #include <jni.h>// 一定要加入的 include檔
產生 dll • 直接在 VC 中 Build Dll 執行程式 在 Jbuilder 中 Build JNIDemo.class 發生錯誤 找不到 dll
執行程式 • 將 Debug中的 dll copy 到 • Java project 的目錄中 完整程式範例: HelloWorld
第一個參數 JNIEnv 存放參數資訊 • jobject this reference
傳入一個字串 1/2 class JNIDemo{ public native void ShowMessage(String Message); public static void main(String args[]){ new JNIDemo.showMessage(“Hello”); } } Java 原始碼方面 static { System.loadLibrary(“JNIC_plusImplement”) ; // 動態的載入 Dll 程式庫 }
// 1. 轉換 Unicode為 C++ 相容的字串 utf-8 const char *str = (env)->GetStringUTFChars(prompt, false); // No copy // 2. 測試印出字串 printf("%s", str); // 3. Release配置的記憶體 (env)->ReleaseStringUTFChars(prompt, str); 傳入一個字串 2/2 C++ 原始碼實作方面 #include <jni.h> #include "JNIDemo_JNIDemo.h" #include <stdio.h> // 實作Java method: ShowMessage(String message) JNIEXPORT void JNICALL Java_JNIDemo_JNIDemo_ShowMessage (JNIEnv *env, jobject obj, jstring prompt) { } 完整範例: PassString
如何傳遞陣列物件並且改值 class JNIDemo{ } // 傳遞一個陣列並且修改其中值的method public native void PassAndChangArrayValue(int[] Buffer); static { System.loadLibrary("JNIC_plusImplement"); // 動態的載入 Dll 程式庫 } // 測試method public static void main(String args[]){ JNIDemo Obj=new JNIDemo(); int []Buffer=new int[100]; // 建立一個 Buffer [] Obj.PassAndChangArrayValue(Buffer); // 傳遞陣列 }
整數陣列 如何傳遞陣列物件並且改值 #include <jni.h> #include "JNIDemo_JNIDemo.h" #include <stdio.h> // 傳遞一個陣列並且修改其中的值 JNIEXPORT void JNICALL Java_JNIDemo_JNIDemo_PassAndChangArrayValue (JNIEnv *env, jobject obj, jintArray arr) { // 1. 取得 Array 的長度 jsize len = (env)->GetArrayLength(arr); // 2. 取出 Array 的資料 jint *body = (env)->GetIntArrayElements(arr, 0);
// 3. 測試: 設定為 123 for(int i=0;i<len;i++) body[i]=123; // 4. 把 Array 的結果 copy back to 呼叫端 (env)->ReleaseIntArrayElements(arr, body, 0); } // end of the native method 完整範例程式: PassArray
如何呼叫視窗的程式 (MFC) • 我們希望能夠在必要的時候 • 呼叫 C++ 所撰寫的視窗程式 Java 如何做 ?
1. 選擇 MFC AppWizard [dll] 2 2. 設定 Dll 名稱 1 如何呼叫視窗的程式 (MFC)-- 建立對話視窗為範例 Finish -> ok 產生 Dll project 檔
1 1. 選擇 Preprocessor 2 2. 加入路徑 設定路徑 • 使得 MFC可以找的到 JNI.h
對應 Java Code的method 進入點 public native void ShowHellow(); 要呼叫 MFC 物件,必須 要加入這行程式 撰寫 MFC 程式 MFC 產生的全區域物件 CVCDLL2App theApp; #include "untitled3_Untitled1.h“ JNIEXPORT void JNICALL Java_untitled3_Untitled1_ShowHellow (JNIEnv *, jobject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); printf("Show The Dialog"); theApp.ShowDialog(); } Java程式產生的 .h 檔 呼叫 theApp.ShowDialog 方法
測試: 加入ShowDialog class CVCDLLApp : public CWinApp { public: CVCDLLApp(); }; void ShowDialog(){ MessageBox(NULL,"test","title",MB_OK); } 完整範例:MFCMessageBox
秀出一個 Dialog 1. 選擇 Resource 選項 2. 滑鼠右鍵: 選 Insert 加入一個Dialog資源 2 1
加入一個按鈕 資源 ID為 IDD_DIALOG1
建立一個Dialog 類別 2 1. 選擇 Class 選項 3 2. 滑鼠點選 VCDLL2 classes 3. 右鍵選擇 New Class … 建立 Dialog 類別 1
結果 撰寫程式 呼叫你的Dialog #include “MyDialog.h” class CVCDLLApp : public CWinApp { public: CVCDLLApp(); }; void ShowDialog(){ MessageBox(NULL,"test","title",MB_OK); MyDialog Obj; // 建立物件 Obj.DoModal(); // 呼叫 Dialog box } 完整範例: MFCDialog
附註: Array Type // 2. 取出 Array 的資料 jint *body = (env)->GetIntArrayElements(arr, 0); 其他type陣列形式 其他陣列的Release形式
加入 C:\jdk1.3.1\include • C:\jdk1.3.1\include\win32 設定 include 路徑
在BCB中實作Java的method int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } #include <untitled3_Untitled1.h> JNIEXPORT void JNICALL Java_untitled3_Untitled1_ShowHellow (JNIEnv *, jobject){ printf("Hello2"); }