Java

Javaのnativeメソッド

作成方法

なにはともれ、共有ライブラリを作成せなあかん

cygwin-gcc

いろいろ方法はあるんだろうけど、一番簡単そうなdefファイルを作ってやる方法。
関数の数が多いと面倒だが。。

javahでヘッダーを作成したら、そのなかから関数の名前を取り出してきて 以下のようなファイル"hoge.def"を作成する。

EXPORTS
 Java_NativeFunctions_initialize_1IMPL
 Java_NativeFunctions_terminate_1IMPL

という感じに、EXPORTSのあとに関数命を連ねる(戻り値とか引数は無視)

で、ソースファイル"hoge.cpp"として、以下のようにコンパイル

g++ -O3 -c hoge.cpp -o hoge.o -O2 -Wall -mrtd -g -mno-cygwin -I<jni.hのある場所>

あとはリンク、ここがキモ。 以下のような感じでhoge.defを指定してやる。

dllwrap -s --export-all --target=i386-mingw32 -mno-cygwin --def hoge.def \
            --driver-name g++ -o ./hoge.dll -mno-cygwin  ./hoge.o -O2

とやるとめでたくhoge.dllができて使えるようになる。 ちなみになにやら激しくワーニングが出たりしているが、キニシナイ。

C++側からJavaメソッドを呼び出す

jclass clazz  = env->FindClass("Hoge");

// staticメソッド
jmethodID mid = env->GetStaticMethodID ( clazz, "methodname", "signiture" );
jobject ret = env->CallStaticObjectMethod(clazz, mid, ... );
// 普通のメソッド
jmethodID mid = env->GetMethodID ( clazz, "methodname", "signiture" );
jobject ret = env->CallObjectMethod(clazz, mid, ... );

シグニチャ(引数)の表現法

GetMethodID, GetStaticMethodIDの時に指定する"signiture"は、メソッドの引数形式。 以下のような感じで指定する。

型のシグニチャーJava の型
Zboolean
Bfloat
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
Lfully-qualified-class ;完全指定のクラス
[typetypeの配列。type[]
( arg-types ) ret-typeメソッドの型
V void(返り値のときのみ指定)
    • int fn ( String[], int );
      ([Ljava/lang/String;I)I
  • [Ljava/lang/String; が第1引数が文字列配列であること
  • 直後のIが第2引数がintであること
  • 括弧の右外側の I が返り値がintであること

を示している。

呼出し方法

クラス(jclass)とメソッドID(jmethodID)を取得したら、あとは適当に引数付きで呼ぶだけだが、 戻り値によって呼ぶ関数が変わる。

戻り値呼ぶ関数
voidvoid CallVoidMethod? (env, obj, methodID, ...)
booleanjboolean CallBooleanMethod? (env, obj, methodID, ...)
bytejbyte CallByteMethod? (env, obj, methodID, ...)
intjint CallIntMethod? (env, obj, methodID, ...)
Objectjobject CallObjectMethod? (env, obj, methodID, ...)
以下、おなじような感じなので省略short, char, long, double

例えば、 String fn(int, String) という関数なら

CallObjectMethod ( env, obj, jintななにか, jobjectななにか );
env->CallObjectMethod ( obj, jintななにか, jobjectななにか );

で行ける。

引数の数とかは可変長関数使ってるので、気にしなくてもよい。
ここで言うobjは jobjectななにかで、メソッドのクラスのインスタンス。

関数名の最後に"V"を付けると、可変長引数ではなく、va_listを渡せるようだ(多分)

jchar CallCharMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

staticメソッドの場合は、 CallStatic?〜 のような名前になって、objの部分が、jclassななにかになる。

CallNonvirtual?〜 なんてものもあるので、virtualじゃない呼び出しもできるのかもしれない(ためしてないけど)

参考文献