需要jni代码的帮助(从本机代码调用java方法)

时间:2011-04-24 11:28:54

标签: java c++ c java-native-interface

我正在编写一个JNI密钥记录器,其原生代码如下所示。

#include "com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper.h"
#include "com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_KeyListener.h"
#include <cstring>
#include <windows.h>
#include <iostream>
#include <stdio.h>

HINSTANCE hinst;
HHOOK hhk;
JNIEnv * thisEnv;
jclass thisClazz;
jmethodID mid;

LRESULT __declspec(dllexport)__stdcall  CALLBACK KeyboardProc(int ,WPARAM , LPARAM );

BOOL WINAPI DllMain(  __in  HINSTANCE hinstDLL,
  __in  DWORD fdwReason,
  __in  LPVOID lpvReserved
  ) {

 hinst = hinstDLL;
 return TRUE;
}

LRESULT __declspec(dllexport)__stdcall  CALLBACK KeyboardProc(int nCode,WPARAM wParam, LPARAM lParam){
    thisEnv->CallStaticVoidMethod(thisClazz, mid, nCode);
    LRESULT RetVal = CallNextHookEx( hhk, nCode, wParam, lParam );
    return  RetVal;
}

JNIEXPORT void JNICALL Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_unhookKeyListener
  (JNIEnv * env, jclass clazz){
    thisEnv = NULL;
    thisClazz = NULL;
    mid = NULL;
    UnhookWindowsHookEx(hhk);
}

JNIEXPORT void JNICALL Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener
  (JNIEnv * env, jclass clazz){
    thisEnv = env;
    thisClazz = clazz;
    mid = env->GetStaticMethodID( clazz, "onKeyPress", "(I)V");
    hhk = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hinst,0);
}

程序的意图是从本机代码通知java程序(静态方法onKeyPress),我将在其中记录密钥并通知用户。我将首先调用hookKeyListener(本机版本:Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener),其中我将注册Windows钩子并存储所有参数(env,jclass和mid)。在回调( KeyboardProc )中,我将使用以前存储的 env jClass mid 通知java程序。最后取消注册。

现在我遇到的问题是,java方法(静态)没有从本机代码调用。我的观察很少。

1&gt;如果在Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener中调用java方法,则成功调用java方法(这意味着我可以调用静态方法)

2&gt;我在KeyboardProc(CallBack)中编写了一些测试代码,比如创建文件和记录密钥,然后它运行良好(这意味着Hook已正确注册,并且在按下按键时也会被调用)

但是我无法从CallBack(KeyboardProc)调用java代码。我对存储的变量(env,jClass,mid)有疑问 - 我可以将这些参数存储到全局变量吗?如果没有,那么我该如何调用来自本机代码的java程序?感谢任何帮助。

以下是我想从本机代码调用的java代码。

package com.webspur.rmtadmin.java.app.keylogger;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.HashMap;

public class KeyloggerHelper {

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

    public interface KeyListener{
        public void onKeyPress(int keyCode);
    }

    private static boolean started = false;
    private static KeyListener keyListener = null;
    private static BufferedWriter writer = null;
    private static HashMap<Integer, String> specialKeys = new HashMap<Integer, String>();

    public static void init(){
        try{
            File logFile = new File("./resources/leylog.txt");
            if(!logFile.exists())
                logFile.createNewFile();
            writer = new BufferedWriter(new FileWriter(logFile, true));
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void start(KeyListener listener){
        keyListener = listener;
        if(!started)
            startInternal();
    }

    public static void stop(){
        keyListener = null;
        if(started)
            stopInternal();
    }

    private static void stopInternal() {
        try{
            unhookKeyListener();
            started = false;
            writer.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static native void unhookKeyListener();

    private static void startInternal(){
        hookKeyListener();
        started = true;
    }

    private static native void hookKeyListener();

    public static void onKeyPress(int keyCode){
        try{
            if(keyListener!=null)
                keyListener.onKeyPress(keyCode);
            writer.append((char)keyCode);
        }catch (Exception e) {
            //ignore..
        }
    }
}

2 个答案:

答案 0 :(得分:1)

您可以在全局变量中存储的唯一内容是:

  1. 字段和方法ID
  2. 全局参考您明确创建
  3. 您无法存储env,也无法存储作为参数传递给您的本地参考。

    您不知道在事件处理程序中将调用哪个线程,因此您必须显式附加。

    总而言之,请参阅http://java.sun.com/docs/books/jni/html/invoke.html

答案 1 :(得分:0)

太多的代码让我费心去阅读,交配。

我不确定为什么你需要本机代码。为什么不用Java编写整个东西,因为它可以响应键盘上的每个键?

您觉得需要本机代码,但回调Java的要求应该是一个提示:不要这样做。你的生活过于复杂,没有收益。想'简单'。