//http://public0821.iteye.com/blog/423941
//http://blog.csdn.net/chinabinlang/article/details/42527337
#include <QCoreApplication>
#include "jni.h"
#include <string>
#include <stdio.h>
#include <iostream>
#include <QLibrary>
#include <QDir>
using namespace std;
char* jstringTostring(JNIEnv* env, jstring jstr);
jstring stoJstring(JNIEnv* env, const char* pat);
//定义一个函数指针,下面用来指向JVM中的JNI_CreateJavaVM函数
typedef jint (*PFunCreateJavaVM)(JavaVM **, void **, void *);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int res;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
JavaVM *jvm;
JNIEnv *env;
/*设置初始化参数*/
//disable JIT,这是JNI文档中的解释,具体意义不是很清楚 ,能取哪些值也不清楚。
//从JNI文档里给的示例代码中搬过来的
options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */
//设置classpath,如果程序用到了第三方的JAR包,也可以在这里面包含进来
options[1].optionString = "-Djava.class.path=.;E:\\"; /* user classes */
//
options[2].optionString = "-Djava.library.path=.;E:\\test\\lib"; /* set native library path */
//设置显示消息的类型,取值有gc、class和jni,如果一次取多个的话值之间用逗号格开,如-verbose:gc,class
//该参数可以用来观察C++调用JAVA的过程,设置该参数后,程序会在标准输出设备上打印调用的相关信息
options[3].optionString = "-verbose:jni"; /* print JNI-related messages */
//设置版本号,版本号有JNI_VERSION_1_1,JNI_VERSION_1_2和JNI_VERSION_1_4
//选择一个根你安装的JRE版本最近的版本号即可,不过你的JRE版本一定要等于或者高于指定的版本号
vm_args.version = JNI_VERSION_1_8;
vm_args.options = options;
vm_args.nOptions = 4;
//该参数指定是否忽略非标准的参数,如果填JNI_FLASE,当遇到非标准参数时,JNI_CreateJavaVM会返回JNI_ERR
vm_args.ignoreUnrecognized = JNI_TRUE;
//加载JVM.DLL动态库
QLibrary mylib("D:\\Java\\jdk1.8.0_45\\jre\\bin\\client\\jvm");
if (false == mylib.load())
{
cout << "jvm.dll Load Failed!" << endl;
return 0;
}
else
{
cout << "jvm.dll Load OK!" <<endl;
}
//取得里面的JNI_CreateJavaVM函数指针
PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)mylib.resolve("JNI_CreateJavaVM");
if (!funCreateJavaVM)
{
cout << "Link to Function JNI_CreateJavaVM Failed!" << endl;
}
else
{
cout << "Link to Function JNI_CreateJavaVM OK!" << endl;
}
//调用JNI_CreateJavaVM创建虚拟机
res = (*funCreateJavaVM)(&jvm, (void**)&env, &vm_args);
if (res < 0)
{
return -1;
}
//查找test.Demo类,返回JAVA类的CLASS对象
jclass cls = env->FindClass("test/Demo");
//根据类的CLASS对象获取该类的实例
jobject obj = env->AllocObject(cls);
//获取类中的方法,最后一个参数是方法的签名,通过javap -s -p 文件名可以获得
jmethodID mid = env->GetMethodID(cls, "append","(Ljava/lang/String;I)Ljava/lang/String;");
//构造参数并调用对象的方法
jstring arg = stoJstring(env, "test_lihailong_");
jstring msg = (jstring) env->CallObjectMethod(obj, mid, arg, 12);
char *output = jstringTostring(env, msg);
cout<< output;
//销毁虚拟机并释放动态库
jvm->DestroyJavaVM();
mylib.unload();
free(output);
return a.exec();
}
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}