нужна помощь по jni-коду (вызов метода java из нативного кода) - PullRequest
0 голосов
/ 24 апреля 2011

Я пишу регистратор ключей 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), где я зарегистрирую хук окон и сохраню все параметры (env, jclass и mid).В обратном вызове ( KeyboardProc ) я уведомлю java-программу, используя ранее сохраненные env , jClass , mid .и, наконец, отмените регистрацию хука.

Теперь проблема, с которой я сталкиваюсь, заключается в том, что Java-метод (статический) не вызывается из собственного кода. Ниже приведены некоторые мои наблюдения.

1> Если вызовJava-метод в Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener, он успешно вызывает java-метод (это означает, что я могу вызывать статические методы)

2> Я написал некоторый тестовый код в KeyboardProc (CallBack), например, создаю файл и записываю в него ключи,работает хорошо (это означает, что Hook зарегистрирован правильно и также вызывается при нажатии клавиши)

Но я не могу вызвать код Java из CallBack (KeyboardProc). У меня есть сомнения по поводу хранимых переменных (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 ]

1 голос
/ 24 апреля 2011

В глобальных переменных вы можете хранить только:

  1. идентификаторы полей и методов
  2. глобальные ссылки, которые вы создаете явно

t хранить env, вы не можете хранить локальные ссылки, которые передаются вам в качестве параметров.

Вы не знаете, какой поток будет вызываться в обработчике событий, поэтому вы должны явно присоединиться.

В целом см. http://java.sun.com/docs/books/jni/html/invoke.html.

0 голосов
/ 24 апреля 2011

Слишком много кода для чтения, приятель.

Я не уверен, зачем тебе нативный код.Почему бы просто не написать все это на Java, поскольку он может реагировать на каждую клавишу на клавиатуре?

Вы чувствуете потребность в нативном коде, но требование обратного вызова в Java должно быть подсказкой: don 'не делай этого.Вы слишком усложнили свою жизнь без вознаграждения.Думай «просто».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...