bool JvmLauncher::startInProcJvm()

in src/main/cpp/bootstrap/jvmlauncher.cpp [185:348]


bool JvmLauncher::startInProcJvm(const char *mainClassName, const std::list<std::string> &args, const std::list<std::string> &options) {
    class Jvm {
    public:

        Jvm(JvmLauncher *jvmLauncher)
            : hDll(0)
            , hSplash(0)
            , jvm(0)
            , env(0)
            , jvmOptions(0)
            , jvmLauncher(jvmLauncher)
        {
        }

        ~Jvm() {
            if (env && env->ExceptionOccurred()) {
                env->ExceptionDescribe();
            }

            if (jvm) {
                logMsg("Destroying JVM");
                jvm->DestroyJavaVM();
            }

            if (jvmOptions) {
                delete[] jvmOptions;
            }

            if (hDll) {
                FreeLibrary(hDll);
            }
            if (hSplash) {
                FreeLibrary(hSplash);
            }
        }

        bool init(const list<string> &options) {
            logMsg("JvmLauncher::Jvm::init()");
            logMsg("LoadLibrary(\"%s\")", jvmLauncher->javaDllPath.c_str());
            {
                PrepareDllPath prepare(jvmLauncher->javaBinPath.c_str());
                hDll = LoadLibrary(jvmLauncher->javaDllPath.c_str());
                if (!hDll) {
                    logErr(true, true, "Cannot load %s.", jvmLauncher->javaDllPath.c_str());
                    return false;
                }
                
                string pref = jvmLauncher->javaBinPath;
                pref += "\\splashscreen.dll";
                const string splash = pref;
                logMsg("Trying to load %s", splash.c_str());
                hSplash = LoadLibrary(splash.c_str());
                logMsg("Splash loaded as %d", hSplash);
            }

            CreateJavaVM createJavaVM = (CreateJavaVM) GetProcAddress(hDll, JNI_CREATEVM_FUNC);
            if (!createJavaVM) {
                logErr(true, true, "GetProcAddress for %s failed.", JNI_CREATEVM_FUNC);
                return false;
            }

            logMsg("JVM options:");
            jvmOptions = new JavaVMOption[options.size() + 1];
            int i = 0;
            for (list<string>::const_iterator it = options.begin(); it != options.end(); ++it, ++i) {
                const string &option = *it;
                logMsg("\t%s", option.c_str());
                if (option.find("-splash:") == 0 && hSplash > 0) {
                    const string splash = option.substr(8);
                    logMsg("splash at %s", splash.c_str());
                    
                    SplashInit splashInit = (SplashInit)GetProcAddress(hSplash, "SplashInit");
                    SplashLoadFile splashLoadFile = (SplashLoadFile)GetProcAddress(hSplash, "SplashLoadFile");
                    
                    logMsg("splash init %d and load %d", splashInit, splashLoadFile);
                    if (splashInit && splashLoadFile) {
                        splashInit();
                        splashLoadFile(splash.c_str());
                    }
                }
                jvmOptions[i].optionString = (char *) option.c_str();
                jvmOptions[i].extraInfo = 0;
            }
            JavaVMInitArgs jvmArgs;
            jvmOptions[options.size()].optionString = (char *) "exit";
            jvmOptions[options.size()].extraInfo    = (void *) &exitHook;
            
            jvmArgs.options = jvmOptions;
            jvmArgs.nOptions = options.size() + 1;
            jvmArgs.version = JNI_VERSION_1_4;
            jvmArgs.ignoreUnrecognized = JNI_TRUE;

            logMsg("Creating JVM...");
            if (createJavaVM(&jvm, &env, &jvmArgs) < 0) {
                logErr(false, true, "JVM creation failed");
                return false;
            }
            logMsg("JVM created.");
            return true;
        }
        typedef jint (CALLBACK *CreateJavaVM)(JavaVM **jvm, JNIEnv **env, void *args);
        typedef void (CALLBACK *SplashInit)();
        typedef int (CALLBACK *SplashLoadFile)(const char* file);

        HMODULE hDll;
        HMODULE hSplash;
        JavaVM *jvm;
        JNIEnv *env;
        JavaVMOption *jvmOptions;
        JvmLauncher *jvmLauncher;
    };

    Jvm jvm(this);
    if (!jvm.init(options)) {
        return false;
    }

    jclass mainClass = jvm.env->FindClass(mainClassName);
    if (!mainClass) {
        logErr(false, true, "Cannot find class %s.", mainClassName);
        return false;
    }

    jmethodID mainMethod = jvm.env->GetStaticMethodID(mainClass, "main", "([Ljava/lang/String;)V");
    if (!mainMethod) {
        logErr(false, true, "Cannot get main method.");
        return false;
    }
    
    jclass jclassString = jvm.env->FindClass("java/lang/String");
    if (!jclassString) {
        logErr(false, true, "Cannot find java/lang/String class");
        return false;
    }

    jstring jstringArg = jvm.env->NewStringUTF("");
    if (!jstringArg) {
        logErr(false, true, "NewStringUTF() failed");
        return false;
    }

    jobjectArray mainArgs = jvm.env->NewObjectArray(args.size(), jclassString, jstringArg);
    if (!mainArgs) {
        logErr(false, true, "NewObjectArray() failed");
        return false;
    }
    int i = 0;
    for (list<string>::const_iterator it = args.begin(); it != args.end(); ++it, ++i) {
        const string &arg = *it;
        const int len = 32*1024;
        char utf8[len] = "";
        if (convertAnsiToUtf8(arg.c_str(), utf8, len))
            logMsg("Conversion to UTF8 failed");
        jstring jstringArg = jvm.env->NewStringUTF(utf8);
        if (!jstringArg) {
            logErr(false, true, "NewStringUTF() failed");
            return false;
        }
        jvm.env->SetObjectArrayElement(mainArgs, i, jstringArg);
    }

    jvm.env->CallStaticVoidMethod(mainClass, mainMethod, mainArgs);
    return true;
}