使用JNI从c ++调用java方法

Tah*_*eri 3 c++ java methods java-native-interface

我正在尝试在JAVA中为特定的usb设备包装一个c ++库.该库支持回调函数,以通知应用程序有关USB设备与PC的连接和分离.

回调函数必须具有如下特定格式:

DWORD callbackFunction(void *params);
Run Code Online (Sandbox Code Playgroud)

所以我在JNI dll中实现了这样的函数,并希望在调用此函数时调用Java wapper中的函数.

问题是JNIENV应该用什么来调用GetObjectClass,GetMethodID和CallVoidMethod?


这是我初始化我的DLL的方式."Set(AttachDetach)Callback"方法接受一个回调函数(第一个参数)和一个void*参数(secondparameter),它将在检测到模块附加/分离时传递给该函数.

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);
}
Run Code Online (Sandbox Code Playgroud)

然后我在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;
}
Run Code Online (Sandbox Code Playgroud)

在我使用AttachCurrentThread之前,我根本无法使用JNIENV指针.但现在该指针的任何其他用途都是成功的,而不是对CallVoidMethod的调用.你看到这里有什么问题吗?

让我补充一点,MyPackage.MyClassCallBacks是一个接口,它的方法是在另一个calss中实现的,即"callBackClass"

Jak*_*rka 5

您需要具有对当前JVM的引用:

JavaVM *jvm;
Run Code Online (Sandbox Code Playgroud)

您可以向C++后端添加一个初始化方法,该方法在程序启动时获取此引用:

JNIEXPORT void JNICALL init(JNIEnv *env, jclass){
    env->GetJavaVM(&jvm);
}
Run Code Online (Sandbox Code Playgroud)

在观察USB attachemnt/detachment时,您可以从这个JavaVM获取JNIEnv,如下所示:

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

//your code here

jvm->DetachCurrentThread();
Run Code Online (Sandbox Code Playgroud)

这是为了使每个USB设备更改创建一个新线程.如果你只使用一个线程进行chceking,你只需要连接一次(在initilizer中,也许?),只要你的本机线程保持连接到JVM,你就会有JNIEnv有效.