I am trying to call a Java method from the code. C code listens to either Escape
, Shift
, Ctrl
key press, then it calls the Java method telling which key was pressed. Following are the snippets that play a role in this.
C Snippet:
mid = (*env)->GetMethodID(env,cls,"callBack","(Ljava/lang/String;)V");
Env = env;
if(called)
switch(param) {
case VK_CONTROL:
printf("Control pressed !\n");
(*Env)->CallVoidMethodA(Env,Obj,mid,"11"); // calling the java method
break;
case VK_SHIFT:
printf("Shift pressed !\n");
(*Env)->CallVoidMethodA(Env,Obj,mid,"10"); // calling the java method
break;
case VK_ESCAPE:
printf("Escape pressed !\n");
(*Env)->CallVoidMethodA(Env,Obj,mid,"1B"); // calling the java method
break;
default:
printf("The default case\n");
break;
}
Java Snippet:
public void callBack(String key) {
String x = KeyEvent.getKeyText(Integer.parseInt(key, 16));
System.out.println(x);
}
When I run the program and press the Escape
key I get this on the console:
Escape pressed !
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x5c8b809a, pid=7588, tid=8088
#
# JRE version: 7.0
# Java VM: Java HotSpot(TM) Client VM (20.0-b01 mixed mode, sharing windows-x86 )
# Problematic frame:
# V [jvm.dll+0x19809a]
#
# An error report file with more information is saved as:
# W:\UnderTest\NetbeansCurrent\KeyLoggerTester\build\classes\hs_err_pid7588.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
I know I am calling the Java function the wrong way, but I don't know where I am wrong. As from the output, it satisfies the case when I press the Escape
key and then an unexpected error occurs.
EDIT:
After the answer by mavroprovato I still get the same errors.
I edited this way:
(*Env)->CallVoidMethodA(Env,Obj,mid,(*Env)->NewStringUTF(Env,"1B"));
EDIT:
I believe you cannot call a java method that takes a String parameter and pass it a
char*
. You should call NewStringUTF first.I think it is due to the UAC feature enabled on your Operating System. This was a bug for Java 6. Read this for further reference.
The reason I say this is because the event to the escape key is fired correctly and the problem only begins as soon as the call to the java method is done.
The JVM is crashing because the
JNIEnv
that is used is not a valid one. There are other issues with the code as well.The Sun JNI documentation is providing very good information regarding threads.
Here comes some parts that are obvious:
Create a
JNI_OnLoad
function in your code. It will be called when the library is loaded. Then cache theJavaVM
pointer because that is valid across threads. An alternative is to call(*env)->GetJavaVM
in theinitializeJNIVars
function but I prefer the first one.In your
initializeJNIVars
you can save theobj
reference by callingObj = (*env)->NewGlobalRef(obj)
.In the
LowLevelKeyboardProc
you will have to get theenv
pointer:AttachCurrentThread(JavaVM *jvm, JNIEnv &env, NULL);
Edit
OK, here are the code that you should add to get it working, I have tried it myself and it works. NB: I have not analyzed what your code is actually doing so I just did some fixes to get it working.
Add these variables among your other global variables:
You can remove your
cls
,mid
,Env
andObj
variables and use mine instead.Create the JNI_OnLoad method where you cache the JavaVM pointer:
Alter your
initializeJNIVars
to look like the following:And finally in your
LowLoevelKeyboardProc
code you will have to add the following:In your
unregisterWinHook
you should delete the global reference so that objects can be GC'd.And that's it.