вызов метода Java из C ++ с использованием JNI - PullRequest
3 голосов
/ 12 марта 2012

Я пытаюсь обернуть библиотеку c ++ для определенного USB-устройства в JAVA.библиотека поддерживает функции обратного вызова для информирования приложения о присоединении и отсоединении USB-устройства к ПК.

функция обратного вызова должна иметь определенный формат, например:

DWORD callbackFunction(void *params);

, поэтому я реализовалподобная функция в jll JNI и хочет вызывать функцию в Java Wapper всякий раз, когда эта функция вызывается.

вопрос в том, что JNIENV я должен использовать для вызова GetObjectClass, GetMethodID и CallVoidMethod из?


Так я инициализирую свою DLL.методы «Set (AttachDetach) Callback» принимают функцию обратного вызова (первый параметр) и параметр void * (второй параметр), которые будут переданы функции при обнаружении присоединения / отсоединения модуля.

JNIEXPORT void JNICALL Java_MyPackage_MyClass_InitializeDLL
(JNIEnv *env, jobject obj, jobject callback)
{
      // Storing callback object in global variable.
    callBackObj = callback;

    env->GetJavaVM(&jvm);

    MyInstance = new MyClass();
    MyInstance ->SetAttachCallback(AttachCallBack, &callBackObj);
    MyInstance ->SetDetachCallback(DetachCallBack, &callBackObj);

      // Testing!
    jclass callBackCls = env->FindClass("MyPackage/MyClassCallBacks");
    jmethodID mid = env->GetMethodID(callBackCls, "attach", "(B)V");
    if (!mid)
        return ; /* method not found */
      //This call here works well
    env->CallVoidMethod(callBackObj, mid, 5);
}

затемЯ установил функцию обратного вызова в DLL для устройства USB, и она успешно вызывается при подключении устройства.

Код, который я вставил в функцию обратного вызова присоединения устройства USB, выглядит следующим образом:

DWORD CALLBACK AttachCallBack(CallbackParams* params)
{
    JNIEnv *env;
    jvm->AttachCurrentThread((void **)&env, NULL);

    jclass callBackCls = env->FindClass("MyPackage/MyClassCallBacks");
    jmethodID mid = env->GetMethodID(callBackCls, "attach", "(B)V");
    if (!mid)
        return -1; /* method not found */
      // This call fails with an access violation Exception
    env->CallVoidMethod(*((jobject *)(params->param)), mid, params->moduleIndex);
      // This fails the same way too
    env->CallVoidMethod(callBackObj, mid, 5);

    jvm->DetachCurrentThread();

    return 0;
}

До того, как я использовал AttachCurrentThread, я вообще не мог использовать указатель JNIENV.но теперь любое другое использование этого указателя является успешным вместо вызова CallVoidMethod.Вы понимаете, что здесь не так?

Позвольте мне добавить, что MyPackage.MyClassCallBacks - это интерфейс, который реализован в другом методе, а именно в "callBackClass"

Ответы [ 4 ]

5 голосов
/ 13 марта 2012

У вас должна быть ссылка на текущую JVM:

JavaVM *jvm;

Вы можете добавить метод инициализации в бэкэнд C ++, который получает эту ссылку при запуске программы:

JNIEXPORT void JNICALL init(JNIEnv *env, jclass){
    env->GetJavaVM(&jvm);
}

И при наблюдении за присоединением / отсоединением USB вы можете получить JNIEnv из этого JavaVM следующим образом:

JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);

//your code here

jvm->DetachCurrentThread();

Это реализовано так, что каждое изменение устройства USB создает новый поток.Если вы используете только один поток для проверки, вам нужно подключиться только один раз (возможно, в инициализаторе?), И тогда у вас будет действительный JNIEnv, пока ваш собственный поток остается подключенным к JVM.

2 голосов
/ 12 марта 2012

Что вам, возможно, придется сделать, это создать очередь в C и ждать ее или опросить ее, используя поток Java. Для него всегда будет доступен текущий JNIEnv.


Кажется, ты не можешь ...

.... сохраните JNIENV из последнего вызова JNI, который его установил, и используйте его повторно.

Ваш обратный вызов, по-видимому, возвращает параметры, которые вы, возможно, передали при настройке обратного вызова. Вы можете сделать один из них JNIENV.

1 голос
/ 20 июля 2012

У меня тоже была такая же проблема.Как будто ссылка на объект, созданный в методе инициализации, не использовалась в других методах.И это действительно так.Решение заключается в инициализации ссылки на объект, которая должна быть инициализирована не просто с помощью

callBackObj = callback

, а с помощью

callbackObj = env->NewGlobalRef(callback)

Та же проблема здесь: Вызов Objective CМетоды Java с использованием JNI

0 голосов
/ 13 марта 2012

Создание инициализации JNI (JNIEnv * env, jclass c (или jobject o)) и

save param #1 JNIEnv

save param #2 jclass (if static) 
   or 
save param #2 jobject (in non-static)

lookup and save the jmethodID(s) for the Java method(s) you will be invoking.  

Хорошей идеей также является отключение JNI (JNIEnv * env, jclass (или jobject)) длясобственное отключение / очистка

...