C/C++アプリケーションからJavaVMを起動し、Javaのクラスを呼び出す実験をしてみました。実に簡単にできるものと感心しました。
JavaVMの起動オプション指定
コマンドラインからJavaを実行する際に指定する書式とほぼ一緒です。JavaVMOption構造体の配列を定義し、それぞれの構造体のoptionStringフィールドにオプション文字列を設定します。
このJavaVMOption構造体の配列は、JavaVMInitArgs構造体のoptionsフィールドにセットします。
JavaVMOption options[3]; options[0].optionString = "-Xmx128m"; options[0].optionString = "-verbose:gc"; options[0].optionString = "-Djava.class.path=C:/home/torutk/myjava/jni"; JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = 3;
JavaVMOption構造体の定義(jni.h)
typedef struct JavaVMOption { char* optionString; void* extraInfo; } JavaVMOption;
JavaVMInitArgs構造体の定義(jni.h)
typedef struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption* options; jboolean ignoreUnrecognized; } JavaVMInitArgs;
JNI_VERSION_1_Xの定義(jni.h)
#define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 #define JNI_VERSION_1_4 0x00010004
JavaVMの起動
JNIEnv* env; JavaVM* jvm; int ret = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); if (ret < 0) { // エラー処理 }
JNI_CreateJavaVM関数の戻り値は、
#define JNI_OK 0 /* success */ #define JNI_ERR (-1) /* unknown error */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error */ #define JNI_ENOMEM (-4) /* not enough memory */ #define JNI_EEXIST (-5) /* VM already created */ #define JNI_EINVAL (-6) /* invalid arguments */
コンパイルと実行
JDKに含まれるJNIのヘッダーファイル2つ、jni.hとjni_md.hを使用するので、インクルードパスにこの両者のあるディレクトリを指定します。
VC++ Toolkit 2003の場合
コンパイル時に、jni.hが入っている%JAVA_HOME%\include、jni_md.hが入っている%JAVA_HOME%\include\win32へのインクルードパスを指定します。
リンカには、インポートライブラリjvm.libとそのパス%JAVA_HOME%\libを指定します。
C:\home\torutk\myjava\jni> cl /IC:\jdk1.5.0\include /IC:\jdk1.5.0\include\win32 /EHsc launch.cpp /link /LIBPATH:C:\jdk1.5.0\lib jvm.lib
実行時には、jvm.dllが必要となるので、環境変数PATHにjvm.dllがあるディレクトリを追加します。jvm.dllは、client用VMとserver用VMと2つ存在します。client用VMの場合、%JAVA_HOME%\jre\bin\clientを指定します。
C:\home\torutk\myjava\jni>PATH=%PATH%;C:\jdk1.5.0\jre\bin\client C:\home\torutk\myjava\jni>launch
JDKのsrc.zipに含まれるlauncher/jvm_md.hには、レジストリを検索してJREのパスを選択する関数GetPublicJREHomeの実装があります。