c++ 如何使用JNI而不必将jvm.dll位置添加到环境变量路径中

7z5jn7bk  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(92)

使JNI工作的一种方法是进入Environment Variables并将jvm.dll所在的文件夹(.../bin/server)添加到UserSystemPath中。但这意味着在客户端机器上,当您的应用启动时,您需要检查是否添加了路径,如果没有,则添加它。
但是,您是否可以不这样做,而是将位置给予给JavaVMOption,或者使用另一种方式,但在代码中,而不必将该位置添加到Environment Variables
我使用的Eclipse Adoptium将与许可协议的应用程序文件一起添加,因此位置将取决于应用程序的放置/安装位置,使Environment Variables的选项有点烦人,因为位置可能会更改,所以您需要删除旧的并在这种情况下每次添加新的。
这是我用来创建JVM的,其中javaLocationstd::string,它是作为包含应用程序文件夹位置的函数的参数给出的:

javaLocation.insert(0, "-Djava.class.path=");
    javaLocation.append("Data\\Java");
    JavaVMInitArgs vm_args;
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = &javaLocation[0];
    vm_args.version = JNI_VERSION_10;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    JNIEnv* env = nullptr;
    jint rc = JNI_OK;
    if (jvm == nullptr) {
        rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    }
    else {
        rc = jvm->AttachCurrentThread((void**)&env, NULL);
    }
    delete[] options;
    if (rc != JNI_OK) {
        if (rc == JNI_EVERSION)
            return "JNI_EVERSION";
        else if (rc == JNI_ENOMEM)
            return "JNI_ENOMEM";
        else if (rc == JNI_EINVAL)
            return "JNI_EINVAL";
        else if (rc == JNI_EEXIST)
            return "JNI_EEXIST";
        else
            return "JNI_FATALERROR";
    }
    return "JNI_CREATED";

这个问题之前在this线程中被问过,并被标记为“This question already has answers here",但不幸的是,那里给出的答案不适用于JNI,它是DLL文件的通用解决方案。

j0pj023g

j0pj023g1#

使用@Botje给出的建议(谢谢!),我再次尝试使用LoadLibraryA,这一次我设法使它工作:

#include <string>
#include <iostream>
#include <chrono>
#include <thread>
#include <jni.h>
#include <Windows.h>

JavaVM* jvm = nullptr;

std::string createVM(std::string location) {
    std::string jvmLocation = location;
    jvmLocation.append("ThirdParty\\Eclipse Adoptium\\jre-17.0.7.7-hotspot\\bin\\servers\\jvm.dll");
    HMODULE hJVMDLL = LoadLibraryA(jvmLocation.c_str());
    typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
    if (hJVMDLL != NULL) {
        fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");
        location.insert(0, "-Djava.class.path=");
        location.append("Data\\Java");
        JavaVMInitArgs vm_args;
        JavaVMOption* options = new JavaVMOption[1];
        options[0].optionString = &location[0];
        vm_args.version = JNI_VERSION_10;
        vm_args.nOptions = 1;
        vm_args.options = options;
        vm_args.ignoreUnrecognized = false;
        JNIEnv* env = nullptr;
        jint rc = JNI_OK;
        if (jvm == nullptr) {
            rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
        }
        else {
            rc = jvm->AttachCurrentThread((void**)&env, NULL);
        }
        delete[] options;
        if (rc != JNI_OK) {
            if (rc == JNI_EVERSION)
                return "JNI_EVERSION";
            else if (rc == JNI_ENOMEM)
                return "JNI_ENOMEM";
            else if (rc == JNI_EINVAL)
                return "JNI_EINVAL";
            else if (rc == JNI_EEXIST)
                return "JNI_EEXIST";
            else
                return "JNI_FATALERROR";
        }
        return "JNI_CREATED";
    }
    else {
        return "ERROR_LOADING_DLL";
    }
}

//This is just a test for a function I have written in Java, which doesn't take any parameters, and returns a String
std::string createIdentification() {
    JNIEnv* env;
    jvm->AttachCurrentThread((void**)&env, NULL);
    jclass jClass = env->FindClass("JavaMethods");

    if (jClass == nullptr) {
        return "ClassNotFound cI";
    }
    else {
        jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
        if (methodID == nullptr) {
            return "MethodNotFound cI";
        }
        else {
            jboolean isCopy;
            jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
            const char* string = env->GetStringUTFChars(jResult, &isCopy);
            std::string result = string;
            env->ReleaseStringUTFChars(jResult, string);

            return result;
        }
    }
}

int main() {
    std::cout << createVM("D:\\Program Files\\MyApp\\").c_str() << std::endl;
    if (jvm != NULL) {
        std::cout << createIdentification().c_str();
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
    return 0;
}

相关问题