I'm trying to implement a Java/C++ binding for a sound streaming class. To keep my example simple, I will reduce it to its seeking method, which is enough to describe my problem:
public abstract class JSoundStream extends SoundStream {
public abstract void seek(float timeOffset);
}
For testing, I use the following implementation:
@Override public void seek(float timeOffset) {
System.out.println("seek(" + timeOffset + ")");
}
The seek
method is a callback method, delegated to by a native C++ functions that serves as a callback for whatever plays the stream. Picture a media player application with a fast forward function as an example:
"Fast forward" button pressed -> Streaming library invokes C++ callback seek
-> Delegate to Java method seek
Note this is just an example, neither the Event Dispatch Thread nor anything else funky is involved.
When an instance of JSoundStream
gets created, a native method is called that will save back both the Java VM pointer (JavaVM*
) as well as the Java object reference (jobject
). I do this because I cannot control when exactly the callback is called, and I know of no way to get the JNI environment or the object live with no Java references whatsoever. So I save back that information at the time of object creation, where I do have the references.
Inside of the C++ seek
method, I'm trying to invoke the Java seek
method this way:
virtual void OnSeek(float timeOffset) {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
env->CallVoidMethod(binding, m_seek, (jfloat)timeOffset);
}
Where binding
is the jobject
, jvm
the Java VM pointer and m_seek
the jmethodID
of the seek
method I obtained before.
However, that invocation of CallVoidMethod
will result in an access violation in jvm.dll
. All of the pointers an开发者_运维问答d values are valid for what I can say, and I did make sure the Java object does not get garbage collected. I believe that storing the jobject
and / or the Java VM pointer is the source of the problem, but then again I cannot see why, because those values are not changing while the program is running.
Can anybody see a problem in the way I am approaching this? How else - without storing references - would I invoke a Java object method from C++ code?
Your approach should be correct, if
Your jobject has been retrieved with
binding = env->NewGlobalRef(binding_passed_as_argument);
You do not call
AttachCurrentThread
from the same thread multiple times - use TLS to store theJNIEnv
pointer.
精彩评论