【Java】【C】【C++】 JNI ~ C++ から Java のソースを呼び出す ~

■ はじめに

http://blogs.yahoo.co.jp/dk521123/33062191.html
で、Java => C++ をやったので、特に必要なかったが、逆もやってみようと。
で、結構、はまったので、メモ。

■ 作成環境

 * WindowsXP
 * Eclipse
 * Visual Studio C++ 2008 Express

■ 作成手順

1) 環境設定

 [1] 実行時には、jvm.dllが必要となるので、環境変数PATHにjvm.dllがあるディレクトリを追加しておく

  * 名前:PATH
  * 値 :;%JAVA_HOME%\jre\bin\client

 ※ これをやっておかないと、VisualStudioでの実行時に
     エラー「jvm dllが見つからなかったため・・・」が表示して実行できない。

2) Eclipseでの作業

 [1] Javaプログラムの作成する(例えば、サンプルの「HellowWorld.java」を参照のこと)

 [2] JARファイルを作成するために、build.xml を作成
  (サンプルの「build.xml」の場合、プロジェクト直下に「lib」フォルダを作成しておく必要がある)

  ※ 具体的な作成方法は、下記の関連記事の「Jarファイル作成」を参照のこと)

 [3] 手順[2] の build.xml を右クリックし、[Run]-[Ant] を選択
  ⇒ プロジェクト直下に、JARファイル「HollowWorld.jar」が作成されてあるはず

3) VisualStudioでの作業

 [1] [ファイル]-[新規作成]-[プロジェクト]-[CLRコンソールアプリケーション]を選択し
   プロジェクト名を入力し(例「cplusAppli」)「OK」押下
 [2] VisualStudioのソリューションエクスプローラにおいて、作成したプロジェクトを右クリックし
  以下を設定する

 * [構成プロパティ]-[C/C++]-[全般]の[追加のインクルードディレクトリ]に以下の3つを追加 
   + (JDKインストールフォルダ)\include\win32(例「C:\Program Files\Java\jdk1.7.0_25\include\win32」)
   + (JDKインストールフォルダ)\include(例「C:\Program Files\Java\jdk1.7.0_25\include」)
 * [構成プロパティ]-[リンカ]-[全般]の[追加のライブラリディレクトリ]に以下を指定
   + (JDKインストールフォルダ)\lib(例「C:\Program Files\Java\jdk1.7.0_25\lib」)
 * [構成プロパティ]-[リンカ]-[入力]の[追加の依存ファイル]に以下を追加
   + jvm.lib (!注意!パスはつけない。★ここではまった。。。★)

 [3] C++のソースを組む(サンプルの「cplusAppli.cpp」を参考に)
 [4] ビルドし、実行する。
  ⇒コンソール画面に「[Hello World, Mike from Java!!]」が表示されるはず。

■ サンプル

Java

HellowWorld.java
package com.cplus;

public class HellowWorld {
   public String getHellowWorld(String name) {
      return "Hellow World, " + name + " from Java!!";
   }
}
build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="javahelloant" default="jar" basedir=".">
    <property name="src.dir" value="src"/>
    <property name="classes.dir" value="classes"/>
    <property name="javadoc.dir" value="docs"/>
    <property name="jar.name" value="HollowWorld.jar"/>
    <property name="jar.dir" value="lib"/>
    <path id="class.path">
        <fileset dir="${jar.dir}" includes="*.jar"/>
    </path>
    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac debug="true" includeAntRuntime="true" srcdir="${src.dir}" destdir="${classes.dir}">
            <classpath refid="class.path"/>
        </javac>
    </target>
    <target name="jar" depends="compile">
        <jar jarfile="${jar.name}" basedir="${classes.dir}"/>
    </target>
    <target name="javadoc">
        <mkdir dir="${javadoc.dir}"/>
        <javadoc destdir="${javadoc.dir}" classpathref="class.path">
            <fileset dir="${src.dir}"/>
        </javadoc>
    </target>
    <target name="clean">
        <delete dir="${classes.dir}"/>
        <delete dir="${javadoc.dir}"/>
        <delete file="${jar.name}"/>
    </target>
</project>

C++

cplusAppli.cpp
// cplusAppli.cpp : メイン プロジェクト ファイルです。

#include "stdafx.h"
#include "jni.h"

using namespace System;

int main(array<System::String ^> ^args)
{
	JNIEnv *env;
	JavaVM *vm;
	JavaVMInitArgs vm_args;
	JavaVMOption options[1];
	options[0].optionString = "-Djava.class.path=C:\\workspace\\SampleEx\\HollowWorld.jar"; // Jarファイルの場所

	vm_args.version = JNI_VERSION_1_6;
	vm_args.options = options;
	vm_args.nOptions = 1;

	// JVMの作成
	int result = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);

	if (result != 0) {
		printf("Fail to create JavaVM (%d).\n", result);
		return 1;
	}
	//JNIHello2.classの取得(クラスパスより検索)
	jclass cls = env->FindClass("com/cplus/HellowWorld");
	if (cls == 0) {
		printf("Fail to find class\n");
		return 1;
	}
	jmethodID cns = env->GetMethodID(cls, "<init>", "()V");
	if (cns==NULL) {
		printf("Fail to find <init>\n");
		return 1;
	}
	jobject obj = env->NewObject(cls, cns);
	
	jmethodID mj = env->GetMethodID(cls, "getHellowWorld", "(Ljava/lang/String;)Ljava/lang/String;");
	if (mj==NULL) {
		printf("Fail to call method\n");
		return 1;
	}

	jstring str = (jstring)env->CallObjectMethod(obj, mj, env->NewStringUTF("Mike"));

	//UTFのchar配列に変換後、コンソールに関数の戻り値を出力。
	printf("[%s]\n", env->GetStringUTFChars(str, NULL));

	vm->DestroyJavaVM();

	Console::Read();
	return 0;
}

参考文献

「1) 環境設定」時に参考にした
http://d.hatena.ne.jp/torutk/20050518/p1
「3) VisualStudioでの作業」時に参考にした
http://d.hatena.ne.jp/teematsu/20091016/1255700227
C++ソースで参考にした
http://d.hatena.ne.jp/kayn_koen/20100116/1263608499

関連記事

JNI ~ Java から C++ のソースを呼び出す ~

https://blogs.yahoo.co.jp/dk521123/33062191.html

Jarファイル作成

https://blogs.yahoo.co.jp/dk521123/6735453.html