Calling java method from C ++ using JNI

I am trying to wrap a C ++ library for a specific usb device in JAVA. The library supports callback functions to inform the application when the USB device is attached and disconnected to the PC.

the callback function must have a specific format:

DWORD callbackFunction(void *params);

      

so I have implemented such a function in the JNI dll and want to call the function in Java wapper whenever this function is called.

The question is, what JNIENV should I use to call GetObjectClass, GetMethodID and CallVoidMethod from?


This is how I initialize my DLL. the "Set (AttachDetach) Callback" methods take a callback function (first parameter) and a void * parameter (second parameter) that will be passed to the function when a module is detected / detached.

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);
}

      

then I set a callback function in the DLL for the USB device and get called successfully when I attach the device.

The code I pasted in response to the USB device callback is the following:

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;
}

      

Before using AttachCurrentThread, I was unable to use the JNIENV pointer at all. but now any other use of this pointer will succeed instead of calling CallVoidMethod. Can you see what's wrong here?

Let me add that MyPackage.MyClassCallBacks is the interface that this method is implemented in other calss, namely "callBackClass"

+3


source to share


4 answers


You need to have a link to the current JVM:

JavaVM *jvm;

      

You can add an initialization method to the C ++ backend that gets this link when the program starts:

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

      



And when you observe USB attachemnt / detachment, you can get JNIEnv from this JavaVM like this:

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

//your code here

jvm->DetachCurrentThread();

      

This is implemented so that each change to the USB device creates a new stream. If you only use one thread for chceking, you only need to attach once (in the initializer, maybe?) And then you will have JNIEnv if your own thread remains attached to the JVM.

+5


source


What you might need is to create a queue in C and wait or poll it with a Java thread. It would always have JNIEnv available.


You can't seem to ...



.... save the JNIENV from the last JNI call that installed and reused it.

The callback appears to return parameters that you may have passed when you customize the callback. You can make one of them JNIENV.

+2


source


I had a problem too. It looked like a reference to an object created in the initialization method was useless in other methods. And indeed it is.
The solution is to initialize a reference to an object that needs to be initialized with more than just

callBackObj = callback

      

but with

callbackObj = env->NewGlobalRef(callback)

      

Same problem here: Objective C calling Java methods using JNI

+1


source


Create JNI init (JNIEnv * env, jclass c (or jobject o)) and

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.  

      

It's a good idea to also disable JNI (JNIEnv * env, jclass (or jobject)) for your own disable / cleanup

0


source







All Articles