我试图使用jni从c ++调用java方法。实际上更多的回调(java - > c ++ - > java) 我通过在.exe(c ++ - > java)中测试它来检查c ++程序是否存在错误 该程序在视觉工作室中完美运行。但是当我将它转换为dll并在java中使用它时失败并崩溃。 我认为它与jvm.dll有关,因为我必须将它包含在我的visual studio项目中。
C ++:
#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "Inter.h"
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=C:\\Users\\SolidSnake\\workspace\\Test\\bin"; //Path to the java source code
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
void callMethod() {
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
jclass m;
jmethodID test;
m = env->FindClass("Main");
test = env->GetStaticMethodID(m,"callbackFromC","()V");
env->CallStaticVoidMethod(m,test);
}
的java:
public final class Main {
public native int callToC();
public static void callbackFromC() {
System.out.println("Hello from C!");
}
public static void main(String[] args) {
System.loadLibrary("Test");
new Main().callToC();
}
}
碰撞:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000007f9aed32ff8, pid=4016, tid=8228
#
# JRE version: Java(TM) SE Runtime Environment (8.0_11-b12) (build 1.8.0_11-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.11-b03 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [Test.dll+0x1a08] JNIEnv_::FindClass+0x28
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
这是程序如何进行的(j:callToC) - &gt; (c:callMethod) - &gt; (Y:callbackFromC)
答案 0 :(得分:1)
我几天前遇到了同样的问题,我找到了问题的解决方案(可能不是最好的解决方案),现在我很自豪地分享它(这个可能对未来的某个人有用)。
当我只有两个项目(C ++ - &gt; Java),即C ++项目调用Java方法时,我的代码运行良好:
void JVM:: Init( const std:: string& javaClassesPath ) {
std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
JavaVMOption options_;
options_.optionString = const_cast<char*>( optionString.c_str() );
// initializing of JVM initial arguments:
JavaVMInitArgs arguments_;
memset( &arguments_, 0, sizeof( arguments_ ) );
arguments_.version = JNI_VERSION_1_6;
arguments_.nOptions = 1;
arguments_.options = &options_;
arguments_.ignoreUnrecognized = 0;
// creating JVM:
long status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ );
if ( status == JNI_ERR )
throw std:: exception("Error: unable to create Java Virtual Machine.\n");
FindClass("ChartBuilder");
}
此代码的调用方式如下:
JVM JChartBuilder( "D:\\Java Src\\Chart\\Chart.jar" ); // the path that will be used as classpath when creating VM (unless this path is specified it will be unable to find the class ChartBuilder)
然后(Java-> C ++ Java) 当我得到第三个项目(Java)必须使用JNI从该C ++项目中调用方法时,我遇到了一个问题,即当一个已经在当前进程中运行时我无法创建VM。但我们可以附加到现有的VM!因此,可以更改上面列出的代码以满足此要求:
void JVM:: Init( const std:: string& javaClassesPath )
{
// initializing of JVM options:
std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
JavaVMOption options_;
options_.optionString = const_cast<char*>( optionString.c_str() );
// initializing of JVM initial arguments:
JavaVMInitArgs arguments_;
memset( &arguments_, 0, sizeof( arguments_ ) );
arguments_.version = JNI_VERSION_1_6;
arguments_.nOptions = 1;
arguments_.options = &options_;
arguments_.ignoreUnrecognized = 0;
// creating JVM or attaching to JVM:
long status;
/* is there any running VMs in the process? */
JavaVM* createdVMs[1] = { nullptr };
jsize numberOfVMs;
status = JNI_GetCreatedJavaVMs(createdVMs, 1, &numberOfVMs);
/* END OF is there any running VMs in the process? */
if( numberOfVMs != 0 )
{ // if VM already runs:
jvm_ = createdVMs[0]; // get the VM
jvm_->AttachCurrentThread((void**)&env_, NULL); // attach to the VM
}
else
{ // if VM does not run:
status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ );
}
if ( status == JNI_ERR )
throw std:: exception("Error: unable to create Java Virtual Machine.\n");
FindClass("ChartBuilder");
}
但那还不是全部。当运行主Java项目(Java-&gt; C ++中的第一个 - &gt; Java)时,我遇到了以下问题:无法找到指定的类ChartBuilder。这是我附加到现有VM,但此虚拟机不知道此类的路径。请记住,当我在C ++中创建VM时,我明确指定了路径。为了解决这个问题,我现在要在运行主Java项目时另外指定类路径。
就是这样。我唯一不喜欢的是在运行主Java项目时需要指定ChartBuilder的类路径,但这个对我来说并不重要,尽管我想知道如何避免这种需求。也许有人知道吗?