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();
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.