C++からjavaを実行する方法。VisualStudio2010とjava8。

参考にさせていただいたサイト。

http://www.ne.jp/asahi/hishidama/home/tech/java/jni_vm.html
https://blogs.yahoo.co.jp/dk521123/33067170.html

概要

諸事情あってC++からJavaを呼び出す際のコードです。
先述のサイト様の実装例といったところです。

環境

  • VisualStudio 2010 sp1
  • java 1.8 191
  • WindowsServer2008 sp1

以下コード

*blog掲載に際し、一部でプロジェクト固有の文字が入っていたため、適当に削除しました。
**メソッドはblog用に一つにしてありますが、jvm使い回し箇所など適宜関数化すればよいかと思います。
#include 
#include "myApp.h"
#include 

#include "jni.h"

#pragma comment(lib, "jvm.lib")

using namespace std;

static JavaVM* vm(NULL);

int cppExecute ( int id ) 
{
    // jvmの用意
    JNIEnv *env;
    JavaVMInitArgs vm_args;
    JavaVMOption options[2];
    options[0].optionString = "-Djava.class.path=xxx.jar";
    options[1].optionString = "-Xmx256m"; //値はblog用に適当
        
    vm_args.version = JNI_VERSION_1_8;
    vm_args.options = options;
    vm_args.nOptions = 2;

    // JVM使いまわしチェック。初回はJVMが未Createなのでそちらのルート。
    // 2回目以降はCreate済みのJVMを使用する。
    if (vm == NULL ) {

        // JVMが存在しない。(初回)
        int result = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
        if (result != 0) {
            // プログラムエラー
            return -1;
        }

    } else {

        // JVMは一度Create済み。
        jint ret = vm->GetEnv((void**)&env, JNI_VERSION_1_8);
        if ( ret == JNI_EDETACHED ) {
            //attache
            ret = vm->AttachCurrentThread((void**)&env, NULL);
            if ( ret != JNI_OK ) {
                return -1;
            }
        } else if ( ret < 0 ){
                return -1;
        }
    }

    //jarの中身の取得(クラスパスより検索)
    jclass cls = env->FindClass("jp/co/myCompany/myApp");    //「.」は「/」とみなす。
    if (cls == 0) {
        return -1;
    }

    // ↑のクラスからメソッド一覧をgetして認識している。
    jmethodID cns = env->GetMethodID(cls, "", "()V");
    if (cns == NULL) {
        return -1;
    }
    jobject obj = env->NewObject(cls, cns);

    // ■■関数の取得~実行部分
    // setParam : URLなど複数のパラメータを一度に設定する。(呼び出し負荷軽減のため)
    // 注意 : blog用に引数は適当なものに変換。URLとかIDとかそれっぽいのが与えられるわけです。
    jmethodID mid = env->GetMethodID(cls, "setParams", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
    env->CallVoidMethod(obj, mid, 
        env->NewStringUTF(testStr),
        env->NewStringUTF(testStr2),
        env->NewStringUTF(testStr3),
        env->NewStringUTF(testStr4),
        env->NewStringUTF(testStr5),
        env->NewStringUTF(testStr6),
        env->NewStringUTF(testStr7),
        env->NewStringUTF(testStr8),
        env->NewStringUTF(testStr9),
        env->NewStringUTF(testStr10),
        env->NewStringUTF(testStr11),
        testInt
    );

    // ■引数検証 : debug用
    //mid = env->GetMethodID(cls, "getClassVars", "()Ljava/lang/String;");
    //jstring jjj = (jstring)env->CallObjectMethod(obj, mid);
    //const char* ccc = env->GetStringUTFChars(jjj, NULL);
    //if (ccc == NULL) {
    //    printf("error");
    //}
    //char *sss = strdup(ccc);
    //env->ReleaseStringUTFChars(jjj, ccc);

    // ■実行
    mid = env->GetMethodID(cls, "myFunc1", "()I");
    int retVal =(int)env->CallIntMethod(obj, mid);

    return retVal;
}


JVM破棄も一応あるけど、どうなんだろうか。
今回プロジェクトではそもそも常駐ものなので、考慮しなかった。

// もしjvmを最終的に使い終わったら後始末。
    //vm->DestroyJavaVM();

    //https://docs.oracle.com/javase/jp/8/docs/technotes/guides/jni/spec/invocation.html#unloading_the_vm
    //DestroyによるJVMアンロードは未対応です、とのこと。

コメント

このブログの人気の投稿

windows10 で nvidia のグラボのcode43現象を解決した

Java : processbuilder 標準出力 タイムアウト

GTX560Ti がおかしい(code 43が出る)(2018年)→解決しました(2019)