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使い回し箇所など適宜関数化すればよいかと思います。
  1. #include
  2. #include "myApp.h"
  3. #include
  4. #include "jni.h"
  5. #pragma comment(lib, "jvm.lib")
  6. using namespace std;
  7. static JavaVM* vm(NULL);
  8. int cppExecute ( int id )
  9. {
  10. // jvmの用意
  11. JNIEnv *env;
  12. JavaVMInitArgs vm_args;
  13. JavaVMOption options[2];
  14. options[0].optionString = "-Djava.class.path=xxx.jar";
  15. options[1].optionString = "-Xmx256m"; //値はblog用に適当
  16. vm_args.version = JNI_VERSION_1_8;
  17. vm_args.options = options;
  18. vm_args.nOptions = 2;
  19. // JVM使いまわしチェック。初回はJVMが未Createなのでそちらのルート。
  20. // 2回目以降はCreate済みのJVMを使用する。
  21. if (vm == NULL ) {
  22. // JVMが存在しない。(初回)
  23. int result = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
  24. if (result != 0) {
  25. // プログラムエラー
  26. return -1;
  27. }
  28. } else {
  29. // JVMは一度Create済み。
  30. jint ret = vm->GetEnv((void**)&env, JNI_VERSION_1_8);
  31. if ( ret == JNI_EDETACHED ) {
  32. //attache
  33. ret = vm->AttachCurrentThread((void**)&env, NULL);
  34. if ( ret != JNI_OK ) {
  35. return -1;
  36. }
  37. } else if ( ret < 0 ){
  38. return -1;
  39. }
  40. }
  41. //jarの中身の取得(クラスパスより検索)
  42. jclass cls = env->FindClass("jp/co/myCompany/myApp"); //「.」は「/」とみなす。
  43. if (cls == 0) {
  44. return -1;
  45. }
  46. // ↑のクラスからメソッド一覧をgetして認識している。
  47. jmethodID cns = env->GetMethodID(cls, "", "()V");
  48. if (cns == NULL) {
  49. return -1;
  50. }
  51. jobject obj = env->NewObject(cls, cns);
  52. // ■■関数の取得~実行部分
  53. // setParam : URLなど複数のパラメータを一度に設定する。(呼び出し負荷軽減のため)
  54. // 注意 : blog用に引数は適当なものに変換。URLとかIDとかそれっぽいのが与えられるわけです。
  55. 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");
  56. env->CallVoidMethod(obj, mid,
  57. env->NewStringUTF(testStr),
  58. env->NewStringUTF(testStr2),
  59. env->NewStringUTF(testStr3),
  60. env->NewStringUTF(testStr4),
  61. env->NewStringUTF(testStr5),
  62. env->NewStringUTF(testStr6),
  63. env->NewStringUTF(testStr7),
  64. env->NewStringUTF(testStr8),
  65. env->NewStringUTF(testStr9),
  66. env->NewStringUTF(testStr10),
  67. env->NewStringUTF(testStr11),
  68. testInt
  69. );
  70. // ■引数検証 : debug用
  71. //mid = env->GetMethodID(cls, "getClassVars", "()Ljava/lang/String;");
  72. //jstring jjj = (jstring)env->CallObjectMethod(obj, mid);
  73. //const char* ccc = env->GetStringUTFChars(jjj, NULL);
  74. //if (ccc == NULL) {
  75. // printf("error");
  76. //}
  77. //char *sss = strdup(ccc);
  78. //env->ReleaseStringUTFChars(jjj, ccc);
  79. // ■実行
  80. mid = env->GetMethodID(cls, "myFunc1", "()I");
  81. int retVal =(int)env->CallIntMethod(obj, mid);
  82. return retVal;
  83. }


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

  1. // もしjvmを最終的に使い終わったら後始末。
  2. //vm->DestroyJavaVM();
  3.  
  4. //https://docs.oracle.com/javase/jp/8/docs/technotes/guides/jni/spec/invocation.html#unloading_the_vm
  5. //DestroyによるJVMアンロードは未対応です、とのこと。

コメント

このブログの人気の投稿

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

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

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