Сбой программы JNI "env-> GetStaticMethodID ()" - PullRequest
2 голосов
/ 26 сентября 2011

Я пытаюсь вызвать функцию Java из C ++.Пока это мой код:

#include <jni.h>

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\MyJavaClasses";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JavaVMCreationResult* cres;
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

Я использую Code :: Blocks с MinGW GCC в Windows 7.
Последняя строка в функции main () вылетает из программы, но компиляторни на что не жалуется.(Комментирование строки jmethodID mid = env->GetSta... делает программу «не сбойной»)
Я использую javap -s Main для получения правильной сигнатуры метода, также класс является допустимым классом Java.

Можете ли вы сказать,мне почему программа вылетает?Этот пример просто показан везде в Интернете, но он не работает для меня.: (

Это класс Java:

public class Main {
    public static void main(String[] args) {
        System.out.println("This is from Java !");
    }
}

РЕШЕНИЕ

Я бы не подумал, мне кажется, что программа не аварийно завершает работу.ранее, когда структура не была инициализирована. Но это действительно было проблемой.
Это полный и рабочий код!

#include <jni.h>

#ifndef null
#define null NULL
#endif

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\Users\\Claudia\\Desktop";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JVMCreationResult* cres = new JVMCreationResult();
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if (cls) {
        printf("Yes !\n");
    }
    else {
        printf("No !\n");
    }
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(cls, mid);

    printf("At end of Program.");
}

Ответы [ 2 ]

5 голосов
/ 26 сентября 2011

Ваша переменная "cres" - это точка в вызове CreateJavaVM, которая никогда не инициализируется, поэтому вы, вероятно, разыменовываете нулевой или иным образом недопустимый указатель в этой точке.

Одним из решений является определение cres (неуказатель на cres) в main и передать указатель на , который , CreateJavaVM в качестве параметра, а затем использовать параметр внутри CreateJavaVM для возврата результата.

Также это хорошая идеяпроверьте, что jvm и env получают ненулевые значения после вызова JNI_CreateJavaVM и что cls и mid также ненулевые после вызовов FindClass и GetStaticMethodID соответственно

2 голосов
/ 27 сентября 2011

cls, вероятно, недействительно.Я предполагаю, что ваша программа потерпела бы крах раньше, если бы 'cres' был нулевым.

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    if(!cres) return -1;
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if(env->ExceptionCheck()) {    // ClassNotFoundException ?
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    if(!cls) return -2;    // this I think is your problem
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

Вы уверены, что ваш classpath был указан правильно?Надеемся, что FindClass ("Main") найдет класс пакета по умолчанию.В любом случае сообщите нам возвращаемое значение, если ваш C / C ++ main () сейчас.

Это возможно для "JavaVM * jvm = cres-> jvm;"для оптимизации, поскольку на «jvm» никогда не ссылаются, а выражение «cres-> jvm» не имеет побочных эффектов.Некоторые комментаторы утверждают, что это должно привести к сбою, хм, да, может быть, если код был сгенерирован и затем выполнен.Но приличный компилятор может увидеть, что это не операция.

Однако утверждение "JNIEnv * env = cres-> env;"не может быть оптимизирован, так как переменная "env" используется позже.Таким образом, мы можем только утверждать, что если cres == 0, то он будет аварийно завершен в этот момент выполнения или до него.Поскольку «env» используется для вызова FindClass (), мы точно знаем, что env! = 0 и, следовательно, cres! = 0.

Я думаю, у вас есть проблема с установкой пути к классу, FindClass () ненайти ваш класс во время выполнения, что приводит к истинности "cls == 0".Вот мой ответ.

РЕДАКТИРОВАНИЕ: Я вижу, что другие утверждают по поводу «cres», однако это не меняет моего первоначального диагноза, но у вас все еще есть ошибка в отношении «cres», измените строку на:

JavaVMCreationResult* cres = new JavaVMCreationResult;

Я думаю, вам повезло, что cres указывает куда-то (вероятно, в стек), затем вы скопировали значения в локальный стек main () и использовали их.Но это не делает технику правильной, так как исходная память, на которую указывает «cres», случайна, поэтому вам повезло, что сбоев не произошло, но вы действительно писали на памяти, которой у вас не должно быть.Используя "cres = new JavaVMCreationResult;"это приводит к тому, что указатель устанавливается на известный действительный блок памяти.

Если вы хотите, чтобы компилятор помог с этой проблемой (т. е. должно появиться предупреждение), попробуйте с MinGW "-Wall" и "-O2"варианты во время компиляции.Следует предупредить о неинициализированном использовании переменной 'cres'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...