I have an application that calls back from C to Java in multiple situations. In some, I have been successful using the technique of calling AttachCurrentThread as described, for example, in various places, e.g.,
http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniref.html#invoke
and recently in this forum
http://forum.java.sun.com/thread.jspa?threadID=763205&tstart=45`
This is an accessibility application and one of the situations I need to callback from is a global keyboard hook. In this context, I call from Java to a C DLL which sets up the keyboard hook using the standard Windows procedure SetWindowsHookEx.
SetWindowsHookEx(
WH_KEYBOARD, // type of hook to install
(HOOKPROC) mykeyboardProc, // address of hook procedure
( HINSTANCE__* )hDll, // handle of application instance
0 // identity of thread to install hook for (all threds) );
The keyboard hook functions in Windows by being "injected" into running applications so that it runs in their process space and therein, apparently, lies the problem.
The keyboard hook gets callbacks from Windows whenever a key is pressed. This is the information I want to learn about back in Java. Our current approach is to have the keyboard hook write the key data to shared memory. Then the Java application makes polling calls into the previously mentioned C DLL which checks the shared memory and returns anything it finds. The C DLL is compiled with the current MinGW compiler.
This procedure works alright-- I can access the information using shared memory in C and polling that from Java. It is, however, a tad slow. I'd like to use a callback from C directly to eliminate the extra layer of polling. I could, of course, do the polling in the C DLL and call back to Java from there. That would eliminate a process switch every time we poll, but would still leave the polling.
In my attempts to set up a direct callback from the keyboard hook to Java, the C code uses AttachCurrentThread using the env pointer obtained from the JNI_OnLoad method. When my application has the focus and I type, I get print statements from the C DLL and the callbacks work fine. When any other application has focus, the callback does not work and there are no print statements. In fact, the keyboard hook crashes and stops responding to any key events.
Since I do not get print statements when another application has focus (or they go into the ether), I do not know directly whether the JNI_OnLoad function actually gets called each time the DLL is loaded into another application. However, the JVM pointer I cache in the JNI_OnLoad function is NULL when I get a key event callback (when another application has focus). I tested this by putting an "exit" call if the cached JVM was NULL in the keyboard procedure (mykeyboardProc above). When any application has focus and I type a key, that application exits. From this I assume that JNI_OnLoad is not getting called, but since the cached JVM is NULL, that is irrelevant.
One option I have attempted is to use JNI_GetCreatedJavaVMs to get a list of the JVMs running on the machine. From this, I hoped to somehow deduce which JVM was running my application and use its pointer. However, despite putting some of the the directories` with the jvm.dll into my library path:
g++ -I/c/Programs/Java/JDK15~1.0_0/include
-I/c/Programs/Java/JDK15~1.0_0/include/win32
-L/c/Programs/Java/JDK15~1.0_0/jre/bin \
....
I get the error:
undefined reference to `JNI_GetCreatedJavaVMs@12'
I would be grateful for any suggestions or solutions.
Rick