- 浏览: 899035 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
天天来注册:
...
try catch finally 用法 -
tadpole_java:
谢谢你的分享。
二十七、Qt数据库(七)QSqlRelationalTableModel(转) -
359449749tan:
android之EditText文本监听(addTextChangedListener) -
michael_wang:
人过留名 多谢分享
Android NOtification 使用 -
wilsonchen:
wangqi0614 写道这个删除是删除所有的把?能不能值删除 ...
Android的SharedPreferences保存与删除数据简单实例
http://blog.csdn.net/mdl13412/article/details/6227487
这个项目是我参加内蒙古挑战杯的比赛项目,由于时间关系,我没时间实现OpenOMR开源项目由JAVA完全向C++的转换,经过我半个多月的尝试,我将OpenOMR中的1/3的代码改写成C++,不过很快我就发现,如果按照这个进度,我是无论如何也无法按时完成工作了,更重要的是Joone人工智能库的算法要是完全移植不是我一个大二学生能够在这么短的时间做到的,于是我放弃JAVA转C++的解决方。
取而代之的是,我使用JAVA做算法的核心,这样就可以用最小的代价快速完成项目,而用C++去调用JAVA的方法,并封装成dll,最后使用C# + IrisSkin2 + 自绘空间的方式制作界面并实现业务逻辑(不要认为C++的步骤多此一举,实际上我的母语是C++,所以做起来非常顺手,反而使我的效率大幅度提升)。
下面说一下我在实现C++调用JAVA的过程中遇到的一些问题。
开发环境: Visual Studio 2010 Ultimate (英文版) + eclipse 3.6.1 + JDK 1.6.0_10
众所周知JAVA依赖jvm,而且执行起来非常繁琐,我这个项目的命令行如下(批处理)
java -cp %cd%/joone-engine-2.0.0RC1/joone-engine.jar;%cd%/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;.;%cd%/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar -Xmx256m openomr.openomr.SheetMusic
不要说用户看这东西会不知所措,就是我看着这东西也是很头疼(虽然我很熟悉dos)
下面讲一下技术难点:
一、不依赖用户机器上的JAVA环境
解决方案:使用本地应用程序集成jre环境,脱离对客户机器jre的依赖
遇见的问题:最开始的时候我认为只需要附带jvm.dll即可实现我的目的,代码如下
view plaincopy to clipboardprint?
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
....................
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
.......................
}
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
....................
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
.......................
}
我将jvm.lib和jvm.dll都放在Debug文件夹中,我发现这时的程序能正确加载jvm.dll,但是执行
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
就提示失败了,为了解决这个问题我开始阅读jni的文档,但是收效甚微,于是开始在各大技术论坛开始寻找解决方案,但是没有找到解决方案,于是我将系统的jre中的jvm.dll加载到程序中,这次程序终于正常跑了起来。
小结:jvm.dll的运行依赖jre中许多dll,而我在项目初期只外挂一个jvm.dll导致了jvm无法正常创建,顺便说一下,解决这个问题从下午5点一直到晚上接近十点才彻底解决,有时候人的惯性思维真的会限制住灵感。
技术难点二:带有目录结构的java类调用
这个纠结了小半天,直接贴代码了
view plaincopy to clipboardprint?
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
using namespace std;
typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
//主函数名,也可改为其他名称,JVM以此查询启动接口。
const char MainName[] ="main";
//虚拟机启动参数总数。
const int JVMOptionCount = 5;
//JVM编译器设定,none为使用默认编译器。
static char Compiler[] = "-Djava.compiler=NONE";
//最小内存
static char MinMB[] = "-Xms256M";
//最大内存
static char MaxMB[] = "-Xmx512M";
//jar包中主函数class所在路径。
static char AppClass[] = "openomr/openomr/SheetMusic";
//需要执行的jar包所在路径,'./'为当前路径简写,多jar包以';'分割。
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
typedef jint (WINAPI* JNICreateJavaVM)(JavaVM**, JNIEnv**, void *);
/**
* Win主函数
**/
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
JVM_DLL = LoadLibraryA("E://工程//Cpp调用Java//Debug//jdk1.6.0_10//jre//bin//client//jvm.dll");
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
//指向本地方法调用接口
JNIEnv* env;
//表示Java虚拟机
JavaVM* jvm;
//设定JVM启动参数
JavaVMInitArgs vm_args;
JavaVMOption options[JVMOptionCount];
/**
*jtl(Java Tools Language)设定:JVM的缺省行为是用“即时”编译器(或JIT[字节代码编译器])执行字节码。
*当加载类时,JIT将类字节码转换成本机代码。使用JIT会导致在每个类加载后有短暂延迟,
*但可提高程序的总体性能。在某些情况下,执行时间可缩短十分之一。
*可用Compiler指定jtl,如将Compiler=foo后,该例中虚拟机将查找名为foo.dll的JIT编译器。
*搜索其它编译器是在jre/bin目录中和系统的PATH上进行的。
*若找不到这样的编译器,虚拟机将缺省使用解释器。
*/
options[0].optionString = Compiler;
//类地址
options[1].optionString = ClassPath;
//lib地址
options[2].optionString = LibraryPath;
//最小内存
options[3].optionString = MinMB;
//最大内存
options[4].optionString = MaxMB;
//PS:此参数用于设定跟踪运行时的信息,暂不需要。
//options[3].optionString = "-verbose:jni";
//使用的jni版本,目前最高为JNI_VERSION_1_6。
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = JVMOptionCount;
vm_args.ignoreUnrecognized = JNI_TRUE;
//启动JVM,并返回结果
int res = createJavaVM(&jvm, &env, &vm_args);
if (res < 0)
{
::MessageBoxA(NULL, "JVM启动失败!", "", MB_OK);
}
//查找目的类
jclass clazz = env->FindClass(AppClass);
if (clazz == 0)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
return cin.get();
}
//取得入口主函数序列号
jmethodID mid = env->GetStaticMethodID(clazz, MainName, "([Ljava/lang/String;)V");
if (0 == mid)
{
::MessageBoxA(NULL, "没有找到主函数!", "", MB_OK);
return cin.get();
}
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);开始执行" << endl;
//main启动
env->CallStaticVoidMethod(clazz, mid, NULL);
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);执行结束" << endl;
//JVM释放
jvm->DestroyJavaVM();
return cin.get();
}
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
using namespace std;
typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
//主函数名,也可改为其他名称,JVM以此查询启动接口。
const char MainName[] ="main";
//虚拟机启动参数总数。
const int JVMOptionCount = 5;
//JVM编译器设定,none为使用默认编译器。
static char Compiler[] = "-Djava.compiler=NONE";
//最小内存
static char MinMB[] = "-Xms256M";
//最大内存
static char MaxMB[] = "-Xmx512M";
//jar包中主函数class所在路径。
static char AppClass[] = "openomr/openomr/SheetMusic";
//需要执行的jar包所在路径,'./'为当前路径简写,多jar包以';'分割。
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
typedef jint (WINAPI* JNICreateJavaVM)(JavaVM**, JNIEnv**, void *);
/**
* Win主函数
**/
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
JVM_DLL = LoadLibraryA("E://工程//Cpp调用Java//Debug//jdk1.6.0_10//jre//bin//client//jvm.dll");
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
//指向本地方法调用接口
JNIEnv* env;
//表示Java虚拟机
JavaVM* jvm;
//设定JVM启动参数
JavaVMInitArgs vm_args;
JavaVMOption options[JVMOptionCount];
/**
*jtl(Java Tools Language)设定:JVM的缺省行为是用“即时”编译器(或JIT[字节代码编译器])执行字节码。
*当加载类时,JIT将类字节码转换成本机代码。使用JIT会导致在每个类加载后有短暂延迟,
*但可提高程序的总体性能。在某些情况下,执行时间可缩短十分之一。
*可用Compiler指定jtl,如将Compiler=foo后,该例中虚拟机将查找名为foo.dll的JIT编译器。
*搜索其它编译器是在jre/bin目录中和系统的PATH上进行的。
*若找不到这样的编译器,虚拟机将缺省使用解释器。
*/
options[0].optionString = Compiler;
//类地址
options[1].optionString = ClassPath;
//lib地址
options[2].optionString = LibraryPath;
//最小内存
options[3].optionString = MinMB;
//最大内存
options[4].optionString = MaxMB;
//PS:此参数用于设定跟踪运行时的信息,暂不需要。
//options[3].optionString = "-verbose:jni";
//使用的jni版本,目前最高为JNI_VERSION_1_6。
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = JVMOptionCount;
vm_args.ignoreUnrecognized = JNI_TRUE;
//启动JVM,并返回结果
int res = createJavaVM(&jvm, &env, &vm_args);
if (res < 0)
{
::MessageBoxA(NULL, "JVM启动失败!", "", MB_OK);
}
//查找目的类
jclass clazz = env->FindClass(AppClass);
if (clazz == 0)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
return cin.get();
}
//取得入口主函数序列号
jmethodID mid = env->GetStaticMethodID(clazz, MainName, "([Ljava/lang/String;)V");
if (0 == mid)
{
::MessageBoxA(NULL, "没有找到主函数!", "", MB_OK);
return cin.get();
}
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);开始执行" << endl;
//main启动
env->CallStaticVoidMethod(clazz, mid, NULL);
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);执行结束" << endl;
//JVM释放
jvm->DestroyJavaVM();
return cin.get();
}
期间遇到的主要问题就是在VS2010上调试程序,始终FindClass查找类失败,为此试了各种办法,先是调用jar,后来又把jar解压。。。都没有成功,于是乎。。。各种纠结。。。下午赶上腾讯的CF有活动,因此申请了个新QQ,去领了把M4A1-A + 防弹衣嘿嘿,小小的YD一下。。。晚上回来突然想法一个问题,就是VS2010的解决方案的目录结构问题
先看一下我的测试项目的目录结构-
大家注意,E:/工程/Cpp调用Java/Debug是可执行文件生成的文件夹,我的库也是直接放在了这个文件夹内,但是这就导致了一个问题,我的代码和exe不再同一个目录,于是
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
这里面的”./“在源码中代表的路径就是E:/工程/Cpp调用Java/Cpp调用Java
而在生成的exe中是E:/工程/Cpp调用Java/
但由于VS2010的特性,它的工作目录不是exe所在目录,而是源码所在目录,这就导致了
static char AppClass[] = "openomr/openomr/SheetMusic";
在加上工作目录组成的绝对路径错误,也就是真正导致FindClass失败的原因
小结:这个问题在很诡异,需要在今后的开发中注意,不能再犯这种低级错误了
这个项目是我参加内蒙古挑战杯的比赛项目,由于时间关系,我没时间实现OpenOMR开源项目由JAVA完全向C++的转换,经过我半个多月的尝试,我将OpenOMR中的1/3的代码改写成C++,不过很快我就发现,如果按照这个进度,我是无论如何也无法按时完成工作了,更重要的是Joone人工智能库的算法要是完全移植不是我一个大二学生能够在这么短的时间做到的,于是我放弃JAVA转C++的解决方。
取而代之的是,我使用JAVA做算法的核心,这样就可以用最小的代价快速完成项目,而用C++去调用JAVA的方法,并封装成dll,最后使用C# + IrisSkin2 + 自绘空间的方式制作界面并实现业务逻辑(不要认为C++的步骤多此一举,实际上我的母语是C++,所以做起来非常顺手,反而使我的效率大幅度提升)。
下面说一下我在实现C++调用JAVA的过程中遇到的一些问题。
开发环境: Visual Studio 2010 Ultimate (英文版) + eclipse 3.6.1 + JDK 1.6.0_10
众所周知JAVA依赖jvm,而且执行起来非常繁琐,我这个项目的命令行如下(批处理)
java -cp %cd%/joone-engine-2.0.0RC1/joone-engine.jar;%cd%/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;.;%cd%/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar -Xmx256m openomr.openomr.SheetMusic
不要说用户看这东西会不知所措,就是我看着这东西也是很头疼(虽然我很熟悉dos)
下面讲一下技术难点:
一、不依赖用户机器上的JAVA环境
解决方案:使用本地应用程序集成jre环境,脱离对客户机器jre的依赖
遇见的问题:最开始的时候我认为只需要附带jvm.dll即可实现我的目的,代码如下
view plaincopy to clipboardprint?
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
....................
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
.......................
}
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
....................
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
.......................
}
我将jvm.lib和jvm.dll都放在Debug文件夹中,我发现这时的程序能正确加载jvm.dll,但是执行
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
就提示失败了,为了解决这个问题我开始阅读jni的文档,但是收效甚微,于是开始在各大技术论坛开始寻找解决方案,但是没有找到解决方案,于是我将系统的jre中的jvm.dll加载到程序中,这次程序终于正常跑了起来。
小结:jvm.dll的运行依赖jre中许多dll,而我在项目初期只外挂一个jvm.dll导致了jvm无法正常创建,顺便说一下,解决这个问题从下午5点一直到晚上接近十点才彻底解决,有时候人的惯性思维真的会限制住灵感。
技术难点二:带有目录结构的java类调用
这个纠结了小半天,直接贴代码了
view plaincopy to clipboardprint?
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
using namespace std;
typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
//主函数名,也可改为其他名称,JVM以此查询启动接口。
const char MainName[] ="main";
//虚拟机启动参数总数。
const int JVMOptionCount = 5;
//JVM编译器设定,none为使用默认编译器。
static char Compiler[] = "-Djava.compiler=NONE";
//最小内存
static char MinMB[] = "-Xms256M";
//最大内存
static char MaxMB[] = "-Xmx512M";
//jar包中主函数class所在路径。
static char AppClass[] = "openomr/openomr/SheetMusic";
//需要执行的jar包所在路径,'./'为当前路径简写,多jar包以';'分割。
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
typedef jint (WINAPI* JNICreateJavaVM)(JavaVM**, JNIEnv**, void *);
/**
* Win主函数
**/
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
JVM_DLL = LoadLibraryA("E://工程//Cpp调用Java//Debug//jdk1.6.0_10//jre//bin//client//jvm.dll");
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
//指向本地方法调用接口
JNIEnv* env;
//表示Java虚拟机
JavaVM* jvm;
//设定JVM启动参数
JavaVMInitArgs vm_args;
JavaVMOption options[JVMOptionCount];
/**
*jtl(Java Tools Language)设定:JVM的缺省行为是用“即时”编译器(或JIT[字节代码编译器])执行字节码。
*当加载类时,JIT将类字节码转换成本机代码。使用JIT会导致在每个类加载后有短暂延迟,
*但可提高程序的总体性能。在某些情况下,执行时间可缩短十分之一。
*可用Compiler指定jtl,如将Compiler=foo后,该例中虚拟机将查找名为foo.dll的JIT编译器。
*搜索其它编译器是在jre/bin目录中和系统的PATH上进行的。
*若找不到这样的编译器,虚拟机将缺省使用解释器。
*/
options[0].optionString = Compiler;
//类地址
options[1].optionString = ClassPath;
//lib地址
options[2].optionString = LibraryPath;
//最小内存
options[3].optionString = MinMB;
//最大内存
options[4].optionString = MaxMB;
//PS:此参数用于设定跟踪运行时的信息,暂不需要。
//options[3].optionString = "-verbose:jni";
//使用的jni版本,目前最高为JNI_VERSION_1_6。
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = JVMOptionCount;
vm_args.ignoreUnrecognized = JNI_TRUE;
//启动JVM,并返回结果
int res = createJavaVM(&jvm, &env, &vm_args);
if (res < 0)
{
::MessageBoxA(NULL, "JVM启动失败!", "", MB_OK);
}
//查找目的类
jclass clazz = env->FindClass(AppClass);
if (clazz == 0)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
return cin.get();
}
//取得入口主函数序列号
jmethodID mid = env->GetStaticMethodID(clazz, MainName, "([Ljava/lang/String;)V");
if (0 == mid)
{
::MessageBoxA(NULL, "没有找到主函数!", "", MB_OK);
return cin.get();
}
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);开始执行" << endl;
//main启动
env->CallStaticVoidMethod(clazz, mid, NULL);
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);执行结束" << endl;
//JVM释放
jvm->DestroyJavaVM();
return cin.get();
}
#include <iostream>
#include <Windows.h>
#include "jdk1.6.0_10/include/jni.h"
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif
#pragma comment(lib, "jvm")
using namespace std;
typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
//主函数名,也可改为其他名称,JVM以此查询启动接口。
const char MainName[] ="main";
//虚拟机启动参数总数。
const int JVMOptionCount = 5;
//JVM编译器设定,none为使用默认编译器。
static char Compiler[] = "-Djava.compiler=NONE";
//最小内存
static char MinMB[] = "-Xms256M";
//最大内存
static char MaxMB[] = "-Xmx512M";
//jar包中主函数class所在路径。
static char AppClass[] = "openomr/openomr/SheetMusic";
//需要执行的jar包所在路径,'./'为当前路径简写,多jar包以';'分割。
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
typedef jint (WINAPI* JNICreateJavaVM)(JavaVM**, JNIEnv**, void *);
/**
* Win主函数
**/
int main()
{
HMODULE JVM_DLL;
// 获取程序自带JVM路径
CHAR JvmFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, JvmFileName, MAX_PATH);
(*strrchr(JvmFileName, '//')) = '/0';
::strcat(JvmFileName, "//jvm.dll");
//获得JVM.DLL启动实体
//JVM_DLL = LoadLibraryA(JvmFileName);
JVM_DLL = LoadLibraryA("E://工程//Cpp调用Java//Debug//jdk1.6.0_10//jre//bin//client//jvm.dll");
if (JVM_DLL == NULL)
{
::MessageBoxA(NULL, "加载不了jvm.dll", "", MB_OK);
}
//JVM内部函数JNI_CreateJavaVM读取
JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
if (createJavaVM == NULL)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
}
//指向本地方法调用接口
JNIEnv* env;
//表示Java虚拟机
JavaVM* jvm;
//设定JVM启动参数
JavaVMInitArgs vm_args;
JavaVMOption options[JVMOptionCount];
/**
*jtl(Java Tools Language)设定:JVM的缺省行为是用“即时”编译器(或JIT[字节代码编译器])执行字节码。
*当加载类时,JIT将类字节码转换成本机代码。使用JIT会导致在每个类加载后有短暂延迟,
*但可提高程序的总体性能。在某些情况下,执行时间可缩短十分之一。
*可用Compiler指定jtl,如将Compiler=foo后,该例中虚拟机将查找名为foo.dll的JIT编译器。
*搜索其它编译器是在jre/bin目录中和系统的PATH上进行的。
*若找不到这样的编译器,虚拟机将缺省使用解释器。
*/
options[0].optionString = Compiler;
//类地址
options[1].optionString = ClassPath;
//lib地址
options[2].optionString = LibraryPath;
//最小内存
options[3].optionString = MinMB;
//最大内存
options[4].optionString = MaxMB;
//PS:此参数用于设定跟踪运行时的信息,暂不需要。
//options[3].optionString = "-verbose:jni";
//使用的jni版本,目前最高为JNI_VERSION_1_6。
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = JVMOptionCount;
vm_args.ignoreUnrecognized = JNI_TRUE;
//启动JVM,并返回结果
int res = createJavaVM(&jvm, &env, &vm_args);
if (res < 0)
{
::MessageBoxA(NULL, "JVM启动失败!", "", MB_OK);
}
//查找目的类
jclass clazz = env->FindClass(AppClass);
if (clazz == 0)
{
::MessageBoxA(NULL, "JNI_CreateJavaVM函数读取失败!", "", MB_OK);
return cin.get();
}
//取得入口主函数序列号
jmethodID mid = env->GetStaticMethodID(clazz, MainName, "([Ljava/lang/String;)V");
if (0 == mid)
{
::MessageBoxA(NULL, "没有找到主函数!", "", MB_OK);
return cin.get();
}
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);开始执行" << endl;
//main启动
env->CallStaticVoidMethod(clazz, mid, NULL);
cout << "env->CallStaticVoidMethod(clazz, mid, NULL);执行结束" << endl;
//JVM释放
jvm->DestroyJavaVM();
return cin.get();
}
期间遇到的主要问题就是在VS2010上调试程序,始终FindClass查找类失败,为此试了各种办法,先是调用jar,后来又把jar解压。。。都没有成功,于是乎。。。各种纠结。。。下午赶上腾讯的CF有活动,因此申请了个新QQ,去领了把M4A1-A + 防弹衣嘿嘿,小小的YD一下。。。晚上回来突然想法一个问题,就是VS2010的解决方案的目录结构问题
先看一下我的测试项目的目录结构-
大家注意,E:/工程/Cpp调用Java/Debug是可执行文件生成的文件夹,我的库也是直接放在了这个文件夹内,但是这就导致了一个问题,我的代码和exe不再同一个目录,于是
static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";
static char LibraryPath[] = "-Djava.library.path=./";
这里面的”./“在源码中代表的路径就是E:/工程/Cpp调用Java/Cpp调用Java
而在生成的exe中是E:/工程/Cpp调用Java/
但由于VS2010的特性,它的工作目录不是exe所在目录,而是源码所在目录,这就导致了
static char AppClass[] = "openomr/openomr/SheetMusic";
在加上工作目录组成的绝对路径错误,也就是真正导致FindClass失败的原因
小结:这个问题在很诡异,需要在今后的开发中注意,不能再犯这种低级错误了
发表评论
-
判断两二叉树相等
2014-05-29 00:13 1100bool IsBSTEqual(BNode* root1, ... -
数据去重
2014-05-29 00:11 773引用 使用数据结构丰富的脚本语言,如Python,利用其中的字 ... -
判断一个整数是否为2的次方幂
2014-05-28 23:56 851/* 判断一个整数是否为2的次方幂 */ bool ... -
实现Comparable接口,进行排序
2014-05-28 23:47 8799import java.util.ArrayList; ... -
Struct2详解
2014-05-21 15:14 887引用 Servlet的缺点: 1、web.xml配置比较多 2 ... -
常用方法
2014-04-25 20:24 746[color=red]String[/color] ... -
java nio和io的比较
2014-04-16 19:49 1703引用 第一部分:简单介绍NIO 服务器在合理时间内处理 ... -
Struts2、Spring3、HIbernate4总结
2014-04-16 10:35 835引用 第一部分:Struts2 1 ... -
Finally的使用总结
2014-04-15 22:02 852//清单一: public class ... -
Fibonacci数列的递归与非递归
2014-04-15 20:57 696//非递归实现 //f(1)=1,f(2)=1,f(n) ... -
Java中的异常
2014-04-14 09:42 604引用 Throwable包括两个子类:Error和Except ... -
JVM的垃圾回收机制
2014-04-13 18:39 831引用 堆被划分为新生代和旧生代, 新生代包含Eden 和 S ... -
集合类总结
2014-04-04 15:54 628引用 一. 总的框架 总的有Collection和Map Co ... -
设计模式之策略模式
2014-04-01 17:07 602main ======================= ... -
设计模式之责任链模式
2014-04-01 16:32 716main ======================= ... -
设计模式之访问者模式
2014-03-31 18:57 831main ======================= ... -
设计模式之工厂模式
2014-03-31 11:33 616main ======================= ... -
设计模式之观察者模式
2014-03-30 15:04 832main =============== ... -
Java虚拟机JVM详解
2014-03-29 12:13 1228引用 第一部分:JVM基本结构 1.什么是JVM 一个java ... -
Java中的反射机制Reflect
2014-03-28 17:17 3571package com.reflect.sym; i ...
相关推荐
Android Studio3.0开发JNI流程,C++调用Java以及Java调用C++,C++/Java互相调用一个简单案例
Android-JNI完整工程,实现c调用java和java调用c
Android JNI基础-利用JNI实现JAVA调用C++代码
jni_c++调用java中的方法 文档中包含(c++与js互相调用的实现)
visual studio 2019下C++通过JNI调用JAVA代码
visual studio 2019下C++通过JNI调用JAVA代码,实现一个简单的打印输出!!!
C++调用java代码验证用户和权限的JNI实现 JAVA代码说明: C++代码说明: 头文件包括三个stdafx.h、jni.h、jni_md.h stdafx.h:vc2005自动生成的,在这个文件中要加入jni相关的头文件如下 jni.h:jdk中自带的...
利用JNI技术实现Java中调用C++编写的函数库示例程序源码,并附上参考JNI文档。 详情见本人博客:Java学习之通过JNI调用C/C++编写的dll链接库(图文教程)(http://write.blog.csdn.net/postlist)
Android Studio项目,此Demo实现Java调用C++函数,然后C++函数回调Java方法、纯C++直接调用Java方法,此为github地址链接
cocos2d-x 通过JNI实现c/c++和Android的java层函数互调, 本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。 (2)通过c++函数调用Android的java层函数,显示一...
C++库封装JNI接口-实现java调用c++
面向开发者的libagora-rtc-sdk-jni.so资源文件,方便各位下载使用libagora-rtc-sdk-jni.so
完整的实现java跨平台调用C程序源码,包含JAVA源码和C源码以及编译后的demo dll。将dll放到jdk bin目录下,java 项目可以直接运行。若要修改dll可以,修改C源码后重新编译生成dll。该demo处理了多线程调用c,全局...
这是一个Android Tcp客户端测试程序,底层由C++实现收发,通过JNI实现C++与JAVA相互调用。本程序完成最基本的收发功能,希望下载的人完善程序后再发布共享到这里。
最近项目中需要使用JNI,所以研究了一下,其中遇到过不少问题,总结一下,让遇到同样问题的人...在C/C++中调用Java的方法一般分为五个步骤:初始化虚拟机、获取类、获取类的方法、创建类对象、调用方法和退出虚拟机。
cocos2d-x 通过JNI实现c/c++和Android的java层函数互调-源码 详情请移步到:http://codingnow.cn/program/992.html
Android-ndk-jni AES加解密 压缩文件里面有 aes加解密 .c .h 文件 还用使用方法
android-aes-jni, 用于 jni& Java的Android AES示例 android-aes-jni git clone https://github.com/panxw/android-aes-jni.git cd android-aes-jni ndk-build
V. Eclipse+CDT+MinGW 进行JAVA调用C/C++ 34 一、 安装eclipse3.2。 34 二、 安装MinGW。 34 1、 下载MinGW 34 2、 安装 34 3、 安装版本 34 4、 选择安装的编译器 34 5、 选择安装路径,下一步 35 6、 等待下载...
JNI调用C++代码和C++层回调java层 demo