write/create listener/callback on a C library
843829Apr 19 2008 — edited Apr 22 2008Can anyone point what's the problem on my code?
I'm writing a DLL, with a thread that will monitor the print spooler and call a java method when a job is added or deleted on a printer.
1) run java main
2) main calls a native method (addJobListener)
3) native method creates a native thread (ThreadProc)
4) native thread (ThreadProc) attaches to jvm
5) (addJobListener) returns
6) PROBLEM: since addJobListener returns, all further jni calls on ThreadProc crashes the code
7) I put a Sleep(9999999) on addJobListener, just as a test, then jni calls on ThreadProc works fine
/* ListenerImpl.java */
public class ListenerImpl implements Listener{
public void metodo() {
System.out.println("ListenerImpl.metodo()");
}
}
/* Teste.java */
public class Teste {
static{
System.loadLibrary("testelib");
}
public static void main(String[] args) throws Exception{
ListenerImpl l = new ListenerImpl();
Teste t = new Teste();
t.addListener(l);
}
public native void addListener(Listener l);
}
/* dllmain.c */
struct param_java{
JavaVM *vm;
jobject obj;
HANDLE h;
};
JNIEXPORT void JNICALL Java_Teste_addListener
(JNIEnv *env, jobject obj, jobject listener){
HANDLE h;//make sure the new thread will be created before this function returns
DWORD threadId;
struct param_java *p;//params for the new thread
(*env)->NewGlobalRef(env, listener);//intend to prevent garbage collect the object when this function returns
JavaVM *vm = NULL;
(*env)->GetJavaVM(env, &vm); //get the JavaVM to attach the new thread
h = CreateEvent(NULL, FALSE, FALSE, NULL);
p = (struct param_java *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct param_java));
p->vm = vm;
p->obj = listener;
p->h = h;
printf("starting new thread\n");
_beginthread(ThreadProc, 0, (void *)p);
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
printf("retuned from addJobListener\n");
//Sleep(9999999);//if I take if off, the jni calls on the thread crashes - wierd!!! It's like JNIEnv I got on the new thread (AttachCurrentThread) is been cleaned or point to same address as the JNIEnv on this function
}
DWORD WINAPI ThreadProc(LPVOID lpParameter){
HANDLE signal;
HANDLE printer;
DWORD change = 0;
int i = 0;
struct parametros_java param = (struct param_java )lpParameter;
JNIEnv *env = NULL;
JavaVM *vm = param->vm;
jobject listener = param->obj;
jmethodID metodo;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_4;
args.name = NULL;
args.group = NULL;
(*vm)->AttachCurrentThread(vm, (void **)&env, &args);
OpenPrinter("HP DeskJet 690C", &printer, NULL);
signal = FindFirstPrinterChangeNotification(printer, PRINTER_CHANGE_ADD_JOB | PRINTER_CHANGE_DELETE_JOB, 0, NULL);
SetEvent(param->h);//notifies the thread on addJobListener the this thread has been started and attached to jvm. That's what it looks like...
for(i = 0; i < 4; i++){
jclass listenerClass = (*env)->GetObjectClass(env, listener);//this code crashed if I take the Sleep(9999999) from the addJobListener
WaitForSingleObject(signal, INFINITE);
FindNextPrinterChangeNotification(signal, &change, NULL, NULL);
if((change & PRINTER_CHANGE_ADD_JOB) == PRINTER_CHANGE_ADD_JOB){
printf("DLL got job\n");
}
if((change & PRINTER_CHANGE_DELETE_JOB) == PRINTER_CHANGE_DELETE_JOB){
printf("DLL lost job\n");
}
metodo = (*env)->GetMethodID(env, listenerClass, "metodo", "()V");//this code crashed if I take the Sleep(9999999) from the addJobListener
(*env)->CallVoidMethod(env, listener, metodo);//this code crashed if I take the Sleep(9999999) from the addJobListener
}
HeapFree(GetProcessHeap(), 0, param);
FindClosePrinterChangeNotification(signal);
ClosePrinter(printer);
(*env)->DeleteGlobalRef(env, listener);
(*vm)->DetachCurrentThread(vm);
}
Edited by: naosbsb on Apr 19, 2008 7:38 PM