Mar*_*røy 1 c c++ java dll jvm
所以我的设置是我有一个由我开发的.dll(A.dll),它在原始应用程序中从外部进程调用,它基本上只是一个.exe文件,我没有源代码(B) .exe).A.dll的目的是与.jar文件进行通信,该文件也是由我开发的(C.jar).所以在应用程序中,"通信流程"如下所示
B.exe - > A.dll - > (通过JNI) - > C.jar
现在,我想要做的就是添加调用之间会A.DLL和C.jar 作为我的测试套件为开发环境的一部分C.jar.到目前为止,我已经创建了另一个.dll(D.dll),它反映了A.dll中的所有函数,但是使用了JNIEXPORT,只是直接调用A.dll中的相应函数.所以这种情况下的"沟通流程"如下:
C.jar开发框架中的单元测试 - >(通过JNI) - > D.dll - > A.dll - >(通过JNI) - > C.jar
在这一点上,一个非常简单的函数调用只是在C.jar中打印出来的东西,它通过整个链条起作用; 从单元测试调用到C.jar的所有方式.然而,当我在A.dll中调用函数时会出现问题,该函数使用CreateJavaVM()创建一个新的JVM ,这会产生以下错误:
初始化VM时出错无法加载本机库:找不到指定的过程
所以基本上我想知道它是否真的可以这样做,或者只是在同一进程中已经有一个正在运行的JVM时调用CreateJavaVM()根本不可能?我知道你不能在同一个进程中多次调用CreateJavaVM(),但是在这种情况下它只被调用一次但是过程中已经存在一个JVM - 你甚至可以在同一个进程中运行多个JVM吗?
解:
感谢@ apangin的回答,下面的代码片段解决了我的问题:
jsize nVMs = 0;
JavaVM** buffer;
jni_GetCreatedJavaVMs = (GetCreatedJavaVMs) GetProcAddress(GetModuleHandle(
TEXT("jvm.dll")), "JNI_GetCreatedJavaVMs");
if (jni_GetCreatedJavaVMs == NULL) {
// stuff
CreateJavaVM(&jvm, (void **) &env, &args);
} else {
jni_GetCreatedJavaVMs(NULL, 0, &nVMs); // 1. just get the required array length
JavaVM** buffer = new JavaVM*[nVMs];
jni_GetCreatedJavaVMs(buffer, nVMs, &nVMs); // 2. get the data
buffer[0]->GetEnv((void **) &env, jni_version); // 3. get environment
jvm = buffer[0];
}
Run Code Online (Sandbox Code Playgroud)
当前的JNI规范明确规定不支持在单个进程中创建多个VM,这实际上是在HotSpot源代码中声明的.
即使你的dll JNI_CreateJavaVM
只调用一次,也不意味着这是整个过程中的第一个调用.事实上,JNI_CreateJavaVM
首先被称为java.exe
或您的IDE(另一个发射器idea.exe
,eclipse.exe
,netbeans.exe
等).
因此,不应盲目创建Java VM,而A.dll
应首先通过调用JNI_GetCreatedJavaVMs来检查当前进程中JVM是否已存在.如果函数返回非空数组,则使用GetEnv或AttachCurrentThread获取JNIEnv*
现有VM,否则创建新VM.