Easy to run Java from C ++

Background information: I am using a Java program and I know how to use Eclipse and Visual Studio.

The ultimate goal: to create a graphical interface, preferably in Visual Studio, which serves as Java.

What I want to do from this question is: a button in C ++ that, when clicked, performs a Java function and returns the results in C ++. (possibly by calling the JVM)

I really doubt the publication of this question here, but I could not find a โ€œdirectโ€ answer anywhere; so I hope someone can show the simplest solution possible for this question.

I am currently considering the following data structures:

  • Sharing data through โ€œsharedโ€ files, such as .txt files (but how do I get Java functions started?)
  • Opening a socket (seems too complicated for this problem)
  • Connection via server (too complicated)
  • Calling the JVM from C ++, which then executes the Java file (I think this is the most sensible way, but it takes a lot of code)

Now I know about the existence of Jace , JNI and SWIG , but I think they are very convenient for creating complex programs, and not for simple interfaces. I donโ€™t want to make a complicated program, so I feel that learning all their commands is pretty annoying.

I also read many Stack Exchange questions asking the same thing, but they all seem to give very complex answers.

So here is my question:

What is the absolute easiest way to execute (if necessary: โ€‹โ€‹a precompiled) Java function from C ++, where C ++ code passes some arguments to this Java function

Thanks in advance.

+7
source share
1 answer

Calling the JVM from C ++, which then executes the Java file (I think this is the most sensible way, but it takes a lot of code)

Yes, this is definitely the smartest way. And with the JNI and API, it doesn't even have much code.

Search jvm.dll

You can try things like hardcoding the path to Oracle JVM jvm.dll or search for a file named jvm.dll in the program folder, but all this is certainly extremely hacky. However, it seems like a pretty simple solution: a registry. The key HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment contains a REG_SZ called CurrentVersion . You can read the value of this key (currently 1.7 ) and open a child key with this name ( HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7 in this example). This key will then contain REG_SZ , called RuntimeLib , which is the path to your jvm.dll . Do not worry about Program files vs Program files (x86) . WOW64 automatically redirects your registry request to HKLM\SOFTWARE\Wow6432Node if you are running a 32-bit process in 64-bit windows, and this key contains the path to the 32-bit jvm.dll . The code:

 #include <Windows.h> #include <jni.h> // C:\Program Files\Java\jdk1.7.0_10\include\jni.h // ... DWORD retval; // fetch jvm.dll path from registry HKEY jKey; if (retval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &jKey)) { RegCloseKey(jKey); // assuming you're using C++/CLI throw gcnew System::ComponentModel::Win32Exception(retval); } TCHAR versionString[16]; // version numbers shouldn't be longer than 16 chars DWORD bufsize = 16 * sizeof(TCHAR); if (retval = RegGetValue(jKey, NULL, TEXT("CurrentVersion"), RRF_RT_REG_SZ, NULL, versionString, &bufsize)) { RegCloseKey(jKey); // assuming you're using C++/CLI throw gcnew System::ComponentModel::Win32Exception(retval); } TCHAR* dllpath = new TCHAR[512]; bufsize = 512 * sizeof(TCHAR); retval = RegGetValue(jKey, versionString, TEXT("RuntimeLib"), RRF_RT_REG_SZ, NULL, dllpath, &bufsize) RegCloseKey(jKey); if (retval) { delete[] dllpath; // assuming you're using C++/CLI throw gcnew System::ComponentModel::Win32Exception(retval); } 

Download jvm.dll and get CreateJavaVM function

This part is pretty simple, you just use LoadLibrary and GetProcAddress :

 HMODULE jniModule = LoadLibrary(dllpath); delete[] dllpath; if (jniModule == NULL) throw gcnew System::ComponentModel::Win32Exception(); typedef int (JNICALL * JNI_CreateJavaVM)(JavaVM** jvm, JNIEnv** env, JavaVMInitArgs* initargs); JNI_CreateJavaVM createJavaVM = (JNI_CreateJavaVM)GetProcAddress(jniModule, "JNI_CreateJavaVM"); 

JVM creation

Now you can call this function:

 JavaVMInitArgs initArgs; initArgs.version = JNI_VERSION_1_6; initArgs.nOptions = 0; JavaVM* jvm; JNIEnv* env; if ((retval = createJavaVM(&jvm, &env, &initArgs)) != JNI_OK) throw gcnew System::Exception(); // beyond the scope of this answer 

Congratulations! There now the JVM is working right inside your process! You are probably starting the JVM when you launch your application. If you are not 100% sure that you only ever call Java code from the thread that the JVM just created, you can throw the env pointer, but you must keep the jvm pointer.

Getting JNI Environment (optional)

So, now you have created the JVM, and your application is running, and then someone clicks on this button. Now you want to call the Java code. If you are 100% sure that you are right now in the thread that created the JVM in the previous step, and you still have an env pointer, you can skip this. Otherwise, do a quick check if the current thread is connected to the JVM and attach it if it is not:

 JNIEnv* env; bool mustDetach = false; jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6); if (retval == JNI_EDETACHED) { JavaVMAttachArgs args; args.version = JNI_VERSION_1_6; args.name = NULL; args.group = NULL; retval = jvm->AttachCurrentThread(&env, &args); mustDetach = true; // to clean up afterwards } if (retval != JNI_OK) throw gcnew System::Exception(); // should never happen invokeJavaCode(env); // next step if (mustDetach) jvm->DetachCurrentThread(); 

Call Java code

Now you are right there, you want to call this Java code, and you even have an env pointer. You want a simple solution, so here is how you call the static method:

 jclass clazz = env->FindClass("com/myself/MyClass"); if (clazz == NULL) throw gcnew System::Exception(); jmethodID mid = env->GetStaticMethodID(clazz, "myStaticMethod", "<signature>"); if (mid == NULL) throw gcnew System::Exception(); <type> returnedValue = env->CallStatic<type>Method(clazz, mid, <arguments>); 

You can use javap -s (command line tool) to determine the signature of the method. <type> can be any primitive type (it must match the return type of the Java method). Arguments can be of any primitive type if they match the arguments of the Java method.

the end

And there you have it: The easiest way to call Java code from C ++ on Windows (in fact, only the first two parts are specific to Windows ...). Oh, and also the most effective. Screw databases and files. Using sockets 127.0.0.1 will be an option, but it is significantly less efficient and probably no less efficient. Wow, this answer is a little longer than I expected. Hope this helps.

+12
source

All Articles