JNI その2:ネイティブコードからJavaメソッドを呼び出す
前記事で参考にした本のネイティブコードからJavaのメソッドを呼ぶサンプルコードが
Javaからネイティブコードを呼んでそこからさらにJavaメソッドを呼ぶ
というなんとも妙もので、実際に動かす例としてはイマイチと思った。
参考にならなそうなので、WEBでJNI関係の記事を検索して主に参考ページ1を参考にした。というか、ほぼそのまま。ただ、C++はわからないのでCでコンパイルできるようにネイティブのコードを少し変えた。
前記事と同じくWindows上で実施。ボーランドC++コンパイラを使用。
作業フォルダはC:\work。
下記のフォルダ、ファイルのツリー表示で括弧で囲ってあるファイルはツール(javac、javah、bcc32、implib)が出力するファイル。
作業フォルダ │ JNIHello2.c │ [JNIHello2.exe] │ [JNIHello2.obj] │ [JNIHello2.tds] │ [jvm_bcc32.lib] │ └─jp └─jnisample [JNIHello2.class] JNIHello2.java
- Javaのコードを作成
- DLLからlibを作成
- ネイティブコードを作成し実行ファイルの作成
- 実行
Javaコードの作成
Javaのクラス、メソッドはネイティブから呼び出すからといって特別なことは特にない。
ただ、staticメソッドの方がクラスを生成しなくて言い分簡単なのでこの例ではstaticメソッドにした。
参考ページ1のJavaコードとの違いは、パッケージをデフォルトパッケージから適当に作ったパッケージ(jp.jnisample)に変えただけ。
package jp.jnisample; public class JNIHello2 { public static String getMessage(){ return "Hello World"; } }
作業フォルダでjavacコマンドを実行しコードをコンパイルする。
C:\work>javac jp\jnisample\JNIHello2.java
DLLからlibを作成
参考ページ1によると、VCならばJava付属のjvm.dllを使えばよいが、ボーランドC++コンパイラの場合は jvm.dll からボーランドC++コンパイラ付属のimplibというツールを使ってlibファイルを作成しそれを使わないといけないそうだ。
下記のようにして jvm_bcc32.lib というlibファイルを作った。
C:\work>implib jvm_bcc32.lib "c:\Program Files\Java\jdk1.6.0_24\jre\bin\client\jvm.dll" Borland Implib Version 3.0.22 Copyright (c) 1991, 2000 Inprise Corporation
ネイティブコードを作成し実行ファイルの作成
はじめの方に書いたが、参考ページ1のネイティブのコードはC++で書かれていて、自分はC++がわからない。よってCのコードとしてコンパイルできるように、ファイル名の拡張子をcに変更し、内容にも若干の修正をした。
#拡張子がcかcppかでボーランドC++コンパイラはC/C++の判定をしているんだろうか?
ネイティブコードの修正点は修正点は以下。
- 変数宣言の場所を変えた。C++ではどこでも変数宣言できるが、Cはブロックの先頭で宣言しなければならない。
- ポインタ変数使い方。正直、忘れてる。とりあえず「env->」と書いてあった場所を「(*env)->」に書き換えた。
- JNI関数を呼ぶときに引数を足した。(*env)->で呼ばれる関数にはenvを、(*vm)->で呼ばれる関数にはvmを第1引数として加えた。
#include <stdio.h> #include <jni.h> int main(){ JNIEnv *env; JavaVM *vm; JavaVMInitArgs vm_args; JavaVMOption options[1]; //JVMオプション配列 int res; jclass cls; jmethodID mid; jstring str; // options[0].optionString = "-Djava.class.path=.\\classes"; /* クラスパス */ options[0].optionString = "-Djava.class.path=."; /* クラスパス */ vm_args.version = JNI_VERSION_1_6; vm_args.options = options; vm_args.nOptions = 1; //JVMオプション個数 vm_args.ignoreUnrecognized = 1; // vm_args.ignoreUnrecognized = TRUE; // TRUEだとwindows.hのインクルードが必要になる //JVMの作成 res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args); if (res < 0) { printf("Fail to create JVM.\n"); return(1); } //JNIHello2.classの取得(クラスパスより検索) cls = (*env)->FindClass(env, "jp/jnisample/JNIHello2"); if (cls == 0) { printf("Fail to find class JNIHello2\n"); return(1); } //取得したクラスからgetMessageというstaticメソッドを取得 mid = (*env)->GetStaticMethodID( env, cls, "getMessage", "()Ljava/lang/String;"); //メソッドを実行し、戻り値Stringを受け取る。 str = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid); //UTFのchar配列に変換後、コンソールに関数の戻り値を出力。 printf("[%s]\n", (*env)->GetStringUTFChars(env, str, NULL)); (*vm)->DestroyJavaVM(vm); return 0; }
これをコンパイル、リンクして実行ファイルを作成。
C:\work>bcc32 -L jvm_bcc32.lib JNIHello2.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland JNIHello2.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
実行
実行するにはパスを追加しなければならない。自分の環境では
C:\Program Files\Java\jdk1.6.0_24\jre\bin\client
を環境変数PATHに追加。
これは、さきほど jvm_bcc32.lib を作るのに使った jvm.dll のある場所にパスが通っていないといけないということだろうか?
パスを追加すると、下記のように実行できた。
C:\work>JNIHello2.exe [Hello World]
参考ページ:
1.civic site >> ネイティブからJavaを呼び出す
2.JNI (Java Native Interface)
3.C/C++からJavaのライブラリを呼ぶ with JNI - #define NO_MONEY 0
4.2006/11/08 日記: Java: シンプルな C言語からJava言語を呼び出すJNIサンプル
Java Native Interface 仕様の目次
« JNI その1:Javaからネイティブコードを呼び出す | Main | PHPメモ030:PostgreSQLを使う »
「Java」カテゴリの記事
- 正規表現メモ(2013.10.07)
- Androidアプリ開発メモ068:Tweenアニメーション(2012.11.18)
- Androidアプリ開発メモ067:NDKのサンプルを動かしてみた(2012.09.10)
- JNI その2:ネイティブコードからJavaメソッドを呼び出す(2012.08.29)
- JNI その1:Javaからネイティブコードを呼び出す(2012.08.26)
The comments to this entry are closed.
« JNI その1:Javaからネイティブコードを呼び出す | Main | PHPメモ030:PostgreSQLを使う »
Comments