有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

c调用java方法有什么问题?

我试图从代码中调用Java方法。C代码侦听EscapeShiftCtrl按键,然后调用Java方法,告知按下了哪个键。以下是在此过程中发挥作用的代码片段

C代码段:

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代码片段:

public void callBack(String key) {
    String x = KeyEvent.getKeyText(Integer.parseInt(key, 16));
    System.out.println(x);
}

当我运行程序并按下Escape键时,我在控制台上看到:

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
#

我知道我调用Java函数的方式不对,但我不知道哪里错了。从输出来看,当我按下Escape键,然后发生意外错误时,它满足这种情况

Link to the LOG FILE

编辑:

在回答了mavroprovato之后,我仍然会得到相同的错误

我这样编辑:

(*Env)->CallVoidMethodA(Env,Obj,mid,(*Env)->NewStringUTF(Env,"1B"));

编辑:

COMPLETE CODE version 1

COMPLETE CODE version 2


共 (3) 个答案

  1. # 1 楼答案

    我认为这是由于您的操作系统启用了UAC功能。这是Java6的一个bug。阅读this以供进一步参考

    我之所以这样说,是因为对escape键的事件被正确触发,并且问题只在对java方法的调用完成后才开始

  2. # 2 楼答案

    我相信您不能调用接受字符串参数并向其传递char*的java方法。你应该先打电话给NewStringUTF

  3. # 3 楼答案

    JVM正在崩溃,因为使用的JNIEnv不是有效的。代码还有其他问题

    {a1}提供了关于线程的非常好的信息

    下面是一些显而易见的部分:

    在代码中创建JNI_OnLoad函数。加载库时将调用它。然后缓存JavaVM指针,因为它跨线程有效。另一种方法是在initializeJNIVars函数中调用(*env)->GetJavaVM,但我更喜欢第一种方法

    initializeJNIVars中,可以通过调用Obj = (*env)->NewGlobalRef(obj)来保存obj引用

    LowLevelKeyboardProc中,必须获取env指针:

    AttachCurrentThread(JavaVM *jvm, JNIEnv &env, NULL);


    编辑

    好的,这里是你应该添加的代码,让它工作,我自己也尝试过,它的工作NB:我没有分析您的代码实际在做什么,所以我只是做了一些修复以使其正常工作

    将这些变量添加到其他全局变量中:

    static JavaVM *javaVM = NULL;
    static jmethodID callbackMethod = NULL;
    static jobject callbackObject = NULL;
    

    您可以删除clsmidEnvObj变量,并使用我的变量

    创建JNI_OnLoad方法,在其中缓存JavaVM指针:

    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
        JNIEnv *env = 0;
    
        if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)) {
            return JNI_ERR;
        }
    
        javaVM = jvm;
    
        return JNI_VERSION_1_4;
    }
    

    initializeJNIVars更改为如下所示:

    void Java_keylogger_TestKeys_initializeJNIVars(JNIEnv *env, jobject obj) {
        jclass cls = (*env)->GetObjectClass(env,obj);
        callbackMethod = (*env)->GetMethodID(env, cls, "callBack", "(Ljava/lang/String;)V");
        callbackObject = (*env)->NewGlobalRef(env, obj);
        if(cls == NULL || callbackMethod == NULL) {
            printf("One of them is null \n");
        }
        called = TRUE;
    }
    

    最后,在LowLoevelKeyboardProc代码中,您必须添加以下内容:

    ...
    WPARAM param = kbhook->vkCode;
    
    JNIEnv *env;
    jint rs = (*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);
    if (rs != JNI_OK) {
        return NULL; // Or something appropriate...
    }
    ...
    
        case VK_ESCAPE:
            printf("Escape pressed !\n");
            jstring message = (*env)->NewStringUTF(env, "1B");
            (*env)->CallVoidMethod(env, callbackObject, callbackMethod, message);
            break;
    ...
    

    unregisterWinHook中,应该删除全局引用,以便可以对对象进行GC

    ...
    (*env)->DeleteGlobalRef(env, callbackObject);
    

    就这样