CallBack JNI help

H

Homer

Can somebody help me please how I can call my callback function in C++:

Java:


class DirectoryWatcher {
public native void watchDirectory();
public native void callBack(String status);


static {
System.loadLibrary("watcher");
}


public void callback(String status) {
System.out.println("Honey, I am home...");
}


public static void main(String[] args) {
DirectoryWatcher dw = new DirectoryWatcher();
dw.watchDirectory();
}



}


C++:

__gc class Watcher
{
public:
void Go(String * s){
.......................
callJavaCallBack();
}


void callJavaCallBack() {
HERE IS THE MISSING PART (WHAT SHOULD I DO HERE? Where
should I get env, obj)
}



};


JNIEXPORT void JNICALL
Java_DirectoryWatcher_callbback(JNIEnv *env, jobject obj, jint depth)
{
(*env)->CallVoidMethod(env, obj,
instanceMethodCall_callback);
}


JNIEXPORT void JNICALL
Java_DirectoryWatcher_watchDirectory(JNIEnv *env, jobject obj)
{
instanceMethodCall_callback = (*env)->GetMethodID(env, cls,
"callback", "()V");

Watcher * w=new Watcher();
w->Go("c:\\test");
return;
}
 
G

Gordon Beaton

Can somebody help me please how I can call my callback function in C++:
[...]

void callJavaCallBack() {
HERE IS THE MISSING PART (WHAT SHOULD I DO HERE? Where
should I get env, obj)
}

If your callback is an instance method, then your setup code should
normally provide an appropriate object for you to use and store a
global reference to it so that it is visible from the place where you
invoke the callback.

In order to get a valid JNIEnv*, the thread invoking the callback
function must attach to the JVM using methods described in the
invocation API (GetCreatedJavaVMs() and AttachCurrentThread(), for
example).

At that point you can lookup the method ID in the target object's
class (e.g. with FindObjectClass() and GetMethodId()), and then use
CallVoidMethod() or similar to make the actual call.

If your callback function needs additional objects as arguments, then
you either need to create them yourself, or your setup code needs to
provide global references to them.

/gordon
 
G

Gordon Beaton

But I am still getting "Unhandled Exception: StackOverflowException."

First, what is that declaration of "struct _jmethodID" doing there?

Your calls to GetMethodID() and CallStaticVoidMethod() do not agree
with each other - either the method is static or it isn't. Use
GetStaticMethodID() or CallVoidMethod().

Finally, you should be checking that each of the calls to JNI
functions has succeeded before you proceed with potentially NULL or
invalid values and a raised exception in the JVM.

/gordon
 
G

Gordon Beaton

BTW. I am using this command to complie (VC++):

cl -Ic:\java\include -Ic:\java\include\win32 -LD hand.cpp
-Fewatcher.dll /clr

If I remove /clr I am getting following error:

hand.cpp(7) : fatal error C1190: managed targeted code requires '#using
<mscorlib.dll>' and '/clr' option


And also I added "struct _jmethodID {};" because I was getting this
error:

Unhandled Exception: System.TypeLoadException: Could not load type
_jmethodID from assembly watcher

I haven't got a clue how to compile DLLs on Windows, but I'll guess
that maybe one of the following is true:

- you haven't included the proper header files from your JDK
- you haven't included the header that javah generated
- you didn't specify the fully qualified classname when you used javah
- you haven't followed *exactly* the names and signatures in the generated header

Someone else might have comments about the compiler command.

/gordon
 
H

Homer

Thanks Gordon for your help. Following your instruction here is what
I've done:

JNIEnv *m_env;
JavaVM *m_vm;
struct _jmethodID {};

JNIEXPORT void JNICALL
Java_DirectoryWatcher_watchDirectory(JNIEnv *env, jobject obj)
{
env->GetJavaVM( &m_vm );
Watcher * w=new Watcher();
w->Go("c:\\test");
return;
}


void doCallback(){
m_vm->AttachCurrentThread( (void**) &m_env, NULL );
jclass cls = m_env->FindClass( "DirectoryWatcher" );
jmethodID mid = m_env->GetMethodID(cls, "callback", "(I)V");
m_env->CallStaticVoidMethod(cls, mid);
}

But I am still getting "Unhandled Exception: StackOverflowException."

Any idea?


Thanks in advance,

Homer
 
H

Homer

BTW. I am using this command to complie (VC++):

cl -Ic:\java\include -Ic:\java\include\win32 -LD hand.cpp
-Fewatcher.dll /clr

If I remove /clr I am getting following error:

hand.cpp(7) : fatal error C1190: managed targeted code requires '#using
<mscorlib.dll>' and '/clr' option


And also I added "struct _jmethodID {};" because I was getting this
error:

Unhandled Exception: System.TypeLoadException: Could not load type
_jmethodID from assembly watcher
 
H

Homer

Thanks Gordon for your quick response. I search on the NET and
everybody was saying add "struct _jmethodID {}; " to your code to not
get TypeLoadException. I have no idea what does it mean.

I added some error printing to my code and I see that methodID I am
getting is zero:

void doCallback(int i){
printf("1111\n");
m_vm->AttachCurrentThread( (void**) &m_env, NULL );
printf("2222\n");
jclass cls = m_env->FindClass( "DirectoryWatcher" );
printf("3333\n");
jmethodID mid = m_env->GetMethodID(cls, "callback", "(I)V");
if(cls == NULL){ printf("error"); return; }
if(mid == 0){printf("mid is Zero"); return; }
printf("4444\n");
m_env->CallVoidMethod(cls, mid);
printf("5555\n");
}

The result is:
1111
2222
3333
mid is Zero


I can email to the code if you want.


Thanks,

Homer
 
G

Gordon Beaton

Thanks Gordon for your quick response. I search on the NET and
everybody was saying add "struct _jmethodID {}; " to your code to not
get TypeLoadException. I have no idea what does it mean.

It seems to me that if you need to do something like that to get a
clean compile, then your JDK is broken or incomplete.
I added some error printing to my code and I see that methodID I am
getting is zero:

void doCallback(int i){
printf("1111\n");
m_vm->AttachCurrentThread( (void**) &m_env, NULL );
printf("2222\n");
jclass cls = m_env->FindClass( "DirectoryWatcher" );
printf("3333\n");
jmethodID mid = m_env->GetMethodID(cls, "callback", "(I)V");
if(cls == NULL){ printf("error"); return; }
if(mid == 0){printf("mid is Zero"); return; }
printf("4444\n");
m_env->CallVoidMethod(cls, mid);
printf("5555\n");
}

The result is:
1111
2222
3333
mid is Zero

I can email to the code if you want.

Please don't.

Did FindClass() succeed? (is cls non-NULL?) Does DirectoryWatcher
belong to a package?

If GetMethodID returns zero, it means that the name or the signature
is wrong, that you're looking in the wrong class, or that you aren't
using the right function to look it up. Note that you must use
GetStaticMethodID() to find a static method, and GetMethodID() to find
a non-static method.

To call a non-static method, you need to pass an object (not its
class) to CallVoidMethod(). If the method is in fact static, use
CallStaticVoidMethod() and pass the class as you've done here.

Use javap -s <classname> to see a list of symbol names and signatures
actually found in the class.

/gordon
 
H

Homer

Thanks so much for your help. It's working now. The trick was to change
everything to Static. (I guess I was not passeing an object after all).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top