I realize this is a question that has already been asked by a few people but their answers did not fix my problem.
I'm currently trying to make a QT application and I have some code written in Java that I'd like to use, so I decided to implement the JNI into my application.
I use the following code to initalize the VM:
JNIEnv* SokoSolver::createVM(JavaVM **JVM){
JNIEnv* Env;
JavaVMInitArgs args;
JavaVMOption options;
options.optionString = "-Djava.class.path=./";
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
args.options = &options;
args.ignoreUnrecognized = 0;
int returnValue = JNI_CreateJavaVM(JVM, (void**)&Env, &args);
if(returnValue < 0 || !Env){
cout << "Unable to launch JVM, Return Value: " << returnValue << endl;
}
return Env;
}
However whenever my code is run I get an error message:
Error occurred during initialization of VM Unable to load native library: Can't find dependent libraries.
I'm using the x86 version of the JVM.lib/JVM.dll, along with the relevant header files. As per the other answers I have changed the path variable in Windows to start with:
C:\Program Files (x86)\Java\jdk1.8.0_74\bin;
C:\Program Files (x86)\Java\jdk1.8.0_74\jre\bin\server;
But when I run my code I still get the exact same errors. Is there any other solutions to this problem? Does it have anything to do with:
options.optionString = "-Djava.class.path=./";
This may be a problem with jdk installed on your system.
Just reinstall jdk 8u92 and add the same path in environment path in your system.
Related
JNI_CreateJavaVM function method does not work and cannot be debugged.
The development environment is win10 x64, jdk version is 1.8
Visual studio 2017 Community Edition Writing a C++ project
I am learning about JNI. I am trying to run The Invocation API. The following URL is an example of the official website documentation.
Click here!
I built the project and added a project dependency that contains jvm.lib. And I put jvm.dll in the project directory. I successfully run this program.
Main.test() is a method of print hello world. But the program exits when executing JNI_CreateJavaVM, the console shows that the return value is 1.
I can't get into debugging, I don't know what happened.
#include <jni.h>
int main() {
printf("begin..........\n");
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";
options[0].optionString = optionString;
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
printf("result=%d", res);
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
jvm->DestroyJavaVM();
return 0;
}
I expect this jvm can be called, but it is forced to exit when the program is executed to `int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
Where am I wrong? Why is it not working?
Exit screenshot
enter image description here
jvm.dll location
enter image description here
jvm.lib linker additional library directories
enter image description here
jvm.lib linker additional Dependencies
enter image description here
Classpath
There is a space between key and equal sign. The space must be removed.
char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";
Classpath value
The java.class.path value must point to the base directory where your compiled .class files are located.
It looks like you're not using a package name, then it's the directory where Main.class is located, so probably it should look something like this:
char optionString[] = "-Djava.class.path=c:/Users/name/MyJavaPrograms/classes";
Access violation
SEGV (or exception 0xC0000005) is also generated intentionally on JVM startup to verify certain CPU/OS features.
see this fine answer: https://stackoverflow.com/a/36258856
In Visual Studio, when the exception dialog is shown, simply turn off that it breaks there. This will prevent you from seeing it again the next time you start the program again.
Java
Just for the sake of completeness: the Java method should look like this:
public class Main {
public static void test(int num) {
System.out.println("Java: test called with '" + num + "'");
}
...
Visual Studio Configuration
The jvm.dll needs to be found. In Visual Studio under Configuration Properties/Debugging/Environment add PATH=%PATH%;<path-to-jdk>\bin\server
For later deployment you could think about putting the whole JRE into a subfolder of your application and reference it with a relative path.
Demo
Finally a brief demo (added a \n here printf("result=%d\n", res); to have a separate line):
In C++ (JNI), I get an already running JVM using the following JNI function:
JNI_GetCreatedJavaVMs(&jvm,1,&vmnb);
Then I attach the current thread using the following code:
jvm->AttachCurrentThread((void**)&env, NULL);
Question: How can I set classpath in that case? Thanks.
Note: Creating a new JVM and passing the classpath in vm_args to the new JVM is not an option for me.
As it is possible to append the classpath inside Java, so I found an alternative way to set classpath inside C++ through Java. As I'm already running JVM, I use the append classpath method (void addPath(String path), that is posted in this answer), inside the Java program that is already running in the JVM. I access the addPath java method from C++ using JNI calls to append the classpath. The classpath passed to addPath method from C++ should not include "-Djava.class.path" and it should be just complete path to the .jar file, i.e. "C:\\folder\\abc.jar". So sequence is: 1) get already running JVM, attach current thread to the JVM, get JNI environment pointer and then call addPath java function (of another running thread) from C++ using JNI. I can now access the classes of new classpath (.jar file) successfully from C++.
I ran into this issue, and I did not have the option to call back into the JVM, so I implemented the whole add_path busniess on the JNI side.
void add_path(JNIEnv* env, const std::string& path)
{
const std::string urlPath = "file:/" + path;
jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
jmethodID getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject classLoaderInstance = env->CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
jclass urlCls = env->FindClass("java/net/URL");
jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", "(Ljava/lang/String;)V");
jobject urlInstance = env->NewObject(urlCls, urlConstructor, env->NewStringUTF(urlPath.c_str()));
env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
std::cout << "Added " << urlPath << " to the classpath." << std::endl;
}
In android OS I want to call an user defined java class API from a standalone code.
i.e. If there is a class "HelloWorldActivity" which has "getint" API . I would like to call this from a native app "nativecaller"
I found post related to this however I was not clear how the implementation was done.
https://groups.google.com/forum/#!topic/android-ndk/_JidHzVWHM8
So here is the code snippet:
#include <jni.h>
#include <cutils/log.h>
#include <stdlib.h>
int main(){
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString = "-Djava.class.path=/data/";
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_FALSE;
/* Create the Java VM */
int res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
if(!res){
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("com/abc/mypackage/HelloWorld"); //it is not able to find the class
if(!cls)LOGE("\n\n\nclass not found!!!");
else{
jmethodID mid = env->GetMethodID(cls, "getint", "(V)I");
env->CallStaticVoidMethod(cls, mid,10);
}
/* We are done. */
jvm->DestroyJavaVM();
}
else
LOGE("\n\n\n\n CreateJAVAVM failed!!");
}
FindClass is returning null.
1.Is it possible to access class inside an activity (an apk)
2.What should -Djava.class.path point to ?
Any input is appreciated!
Dalvik provides a command called dalvikvm, which isn't too far removed from what you're trying to do. It's just a command-line wrapper for libdvm.so (try adb shell dalvikvm -help). You can see the source code here.
Try a quick test: instead of looking up your application class, look up something that you know will be there (say, java/lang/String). That will tell you if the VM is able to do anything at all.
On a device, BOOTCLASSPATH will already be configured in your environment (adb shell printenv BOOTCLASSPATH), but CLASSPATH will not. Set the CLASSPATH environment variable to a colon-separated list of .jar or .apk files, not a list of directories.
You will need to run as root, so that your command-line application has permission to create an entry in /data/dalvik-cache for your APK. (If such an entry already exists, you may not need to be root.)
If something doesn't work, check the logcat output for details.
I'm trying to create JVM usin JNI. I'm using win 7 64 bits OS. On line JNI_CreateJavaVM my program crashes. I decided to compile my program using 64 bit compiler and got following error:
Error 1 error LNK2001: unresolved external symbol __imp_JNI_CreateJavaVM
Where is the point I should start to look for linking problem and why my program crashes in 32 bit mode?
void createJVM()
{
JavaVMInitArgs vm_args;
JavaVMOption options[4];
int n = 0;
char * str;
str= new char[1000];
sprintf(str, "-Djava.class.path=%S\\tst.jar", myPath);
options[n++].optionString = str;
str= new char[1000];
sprintf(str, "-Djava.library.path=%S\\lib;%S", myPath, myPath);
options[n++].optionString = str;
str= new char[1000];
sprintf(str, "-Duser.dir=%S", myPath);
options[n++].optionString = str;
vm_args.version = JNI_VERSION_1_4;
vm_args.nOptions = n;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
have you added 'jvm.lib' as Additional Dependency in your project?
furthermore, you need to specify the location of jvm.lib in Additional Library Directories...
also please note that for 64-bit application, you would need to point to the 64-bit library, otherwise linker won't link
You can find those settings in the Configuration Properties->Linker area.
hope this information helps you out.
Cheers,
Since I can't wote up (still less than 15 reputation) I just want to confirm that Naytzyrhc solution worked for me.
Just to clarify it a bit more, in Visual Studio Express 2013 (v12) you should go to:
Project -> [YourProjectName] Properties... -> Linker -> General -> Additional Library Directories
for adding lib folder to additional library directories, and:
Project -> [YourProjectName] Properties... -> Linker -> Input -> Additional Dependencies
for adding jvm.lib to additional dependencies.
I'm trying to call my java class from c++ (ms vc 2008) with JNI, but the problem is that FindClass works only when there are not imported packages in my java class. If I add any package (for example java.lang.String or java.io.File) the FindClass fails and returns no value. Why?
C++ CODE: /////////////////////////////////////
JNIEnv *env;
JavaVM * jvm;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=c:\\mypackage.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(env == NULL)
printf("\nJVM Failed\n");
jclass cls = env->FindClass("mypackage/test/MyClass");
if(cls==0)
{
printf("\nFindClass Failed\n");
}
JAVA CODE: /////////////////////////////////////
package mypackage.test;
import java.io.File; //if I comment this row, FindClass works...
public class MyClass {
}
UPDATE:
THIS IS MY CODE: http://www.sendspace.com/file/233tfm
copy in C:\JNITest
change the working directory in the properties\debug settings of the project
check the optionString in JNI_test1.cpp
many thanks,
Riccardo
The VM cannot find rt.jar and all the other classes. This question suggests to run JNI_GetDefaultJavaVMInitArgs(&vm_args); before you set other options.
I guess it could be because your class path is only c:\mypackage.jar when you create the JVM. I think the system class path has to be specified. Class path can be set as options.optionString = "-Djava.class.path=c:\mypackage.jar;C:\jdk1.6.0_18\jre\lib\rt.jar"; Please change based on where rt.jar is on your system....
I have found the problem. If I select in Eclipse\Jar Export\ the option "Export generated class files and resources" AND I put some import in my java class, the generated JAR file will not include any .class file. Instead the option "Export all output folders for checked projects" works anytime. I don't know why, but I will investigate.