2015/06/08

Java native interface C++

強者我朋友最近要用前端調用底層,上星期提供給的方式無法解決他的需求,因此他吩咐我我回去想想看有沒有方法可以幫他解決
頭腦一閃,突然想到JNI應該可以讓他解決問題,但距離上次使用JNI已經是三年前了…
想說三年前才開使撰寫部落格,所以應該會有JNI的筆記吧…
沒想到將舊文翻一翻之後才知道原來我當初沒寫筆記啊…
這次就花時間來寫筆記了啊…囧
免得三年後又用到…

先開啟一個新專案,選擇Win32


要給Java調用,所以選擇DLL並按下完成


接著找到安裝JDK路徑底下的include/jni.h以及/include/win32/jni_md.h,將兩個標頭檔複製到專案資料夾內,再專案資料夾內的兩個標頭檔新增至專案





開啟stdafx.h,下方程式碼貼入即可



標頭檔:
// stdafx.h : 可在此標頭檔中包含標準的系統 Include 檔,
// 或是經常使用卻很少變更的
// 專案專用 Include 檔案
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // 從 Windows 標頭排除不常使用的成員
// Windows 標頭檔: 
#include <windows.h>
// JNI 標頭檔
#include "jni.h"

#ifndef _Included_CYFang
#define _Included_CYFang
#ifdef __cplusplus  
extern "C" {
#endif
 //Java_ClassName_MethodName
 JNIEXPORT jobjectArray JNICALL Java_CYFang_getInfo(JNIEnv *env, jobject obj);
#ifdef __cplusplus
}
#endif
#endif


以下程式碼貼到Win32Project.cpp內
程式碼:
// Win32Project.cpp : 定義 DLL 應用程式的匯出函式。
//

#include "stdafx.h"


JNIEXPORT jobjectArray JNICALL
Java_CYFang_getInfo(JNIEnv *env, jobject obj)
{

 //Array
 jobjectArray array = env->NewObjectArray(3,
  env->FindClass("java/lang/String"), 0);
 char *name = "CYFang";
 char *number = "11223344";
 char *score = "90";

 env->SetObjectArrayElement(array, 0, env->NewStringUTF(name));
 env->SetObjectArrayElement(array, 1, env->NewStringUTF(number));
 env->SetObjectArrayElement(array, 2, env->NewStringUTF(score));

 ZeroMemory(name, strlen(name));
 ZeroMemory(number, strlen(number));
 ZeroMemory(score, strlen(score));

 return array;
}


JNI有它的命名規則,已我自訂的方法為例『JNIEXPORT jobjectArray JNICALL Java_CYFang_getInfo』
JNIEXPORT:固定欄位
jobjectArray:方法型別
JNICALL:固定欄位
JAVA:固定的欄位
CYFang:Java的類別名稱
getInfo:方法名稱

關於方法型別可以參考『JNI Types and Data Structures
接著建制該專案,輸出成功則會在專案資料夾底下找到DLL
WIN32使用者,將該DLL放置C:windows\system32底下
WIN64使用者,將該DLL放置C:windows\system64底下

接著開啟Eclipse,新增Java專案名稱隨意
接著新增Class名稱為JNI所設定的ClassName




Java程式碼:
public class CYFang {
 static {
  System.loadLibrary("Win32Project");
 }

 native String[] getInfo();

 public static void main(String[] args) {
  CYFang cyFang = new CYFang();
  for (String str : cyFang.getInfo()) {
   System.out.println(str);
  }

 }
}



執行結果: