寻 JNI高手帮忙解决一个问题,万分感谢!

blackkettle 2012-08-21 08:50:56
JNI 达人,我改写了一个全局监听的 java调用 dll的代码,可是一运行就 JVM crash.

请达人帮我看看是什么原因,非常感谢!


运行环境:

OS: Windows XP Build 2600 Service Pack 3

CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 23 stepping 10, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1

Memory: 4k page, physical 2091204k(875764k free), swap 4029236k(2644760k free)

vm_info: Java HotSpot(TM) Client VM (20.4-b02) for windows-x86 JRE (1.6.0_29-b11), built on Oct 3 2011 01:01:08 by "java_re" with MS VC++ 7.1 (VS2003)


Example.java
package jni;

public class Example implements KeyboardEventListener {

static GlobalEventListener gl;

public static void main(String[] args) throws Exception
{
Example inst = new Example();
gl = new GlobalEventListener();
gl.addKeyboardEventListener(inst);
}

public void GlobalKeyPressed( KeyboardEvent event )
{

System.out.println( "Key Pressed: " + event.getVirtualKeyCode() );
}

public void GlobalKeyReleased( KeyboardEvent event )
{
System.out.println( "Key Released: " + event.getVirtualKeyCode() );
}

}



GlobalEventListener.java
package jni;

public class GlobalEventListener
{
PoolHook pt;
public GlobalEventListener()
{
pt = new PoolHook(this);
pt.start();

}

protected javax.swing.event.EventListenerList listenerList = new javax.swing.event.EventListenerList();

public void addKeyboardEventListener(KeyboardEventListener listener)
{
listenerList.add( KeyboardEventListener.class, listener );
}

public void removeKeyboardEventListener(KeyboardEventListener listener)
{
listenerList.remove( KeyboardEventListener.class, listener );
}


void keyPressed(KeyboardEvent event)
{
Object[] listeners = listenerList.getListenerList();
for ( int i = 0; i < listeners.length; i += 2 )
{
if ( listeners[ i ] == KeyboardEventListener.class )
{
( (KeyboardEventListener)listeners[i + 1] ).GlobalKeyPressed( event );
}
}
}

void keyReleased(KeyboardEvent event)
{
Object[] listeners = listenerList.getListenerList();
for ( int i = 0; i < listeners.length; i += 2 )
{
if ( listeners[ i ] == KeyboardEventListener.class )
{
( (KeyboardEventListener)listeners[i + 1] ).GlobalKeyReleased( event );
}
}
}


}





KeyboardEventListener.java
package jni;

import java.util.*;

public interface KeyboardEventListener extends EventListener
{
public void GlobalKeyPressed( KeyboardEvent event );
public void GlobalKeyReleased( KeyboardEvent event );
}


class KeyboardEvent extends EventObject
{
private static final long serialVersionUID = 2341653211621224652L;
boolean ts, ap, ek;
int vk;

public KeyboardEvent( Object source, boolean ts, int vk, boolean ap, boolean ek )
{
super(source);
this.ts = ts;
this.vk = vk;
this.ap = ap;
this.ek = ek;
}

public boolean getTransitionState()
{
return ts;
}

public long getVirtualKeyCode()
{
return vk;
}

public boolean isAltPressed()
{
return ap;
}

public boolean isExtendedKey()
{
return ek;
}

public boolean equals( KeyboardEvent event )
{
if( event.getVirtualKeyCode() == vk )
{
if( event.isExtendedKey() == ek )
{
if( event.isAltPressed() == ap )
{
return true;
}
}
}
return false;
}
}



SysHook.java
package jni;

class PoolHook extends Thread
{
SysHook hook;
GlobalEventListener g_gl;
PoolHook(GlobalEventListener gl)
{
g_gl = gl;
}


public void run()
{
hook = new SysHook();
hook.registerHook(g_gl);
}

}

class SysHook
{

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

void processKey( boolean ts ,int vk, GlobalEventListener gl)
{
KeyboardEvent event = new KeyboardEvent( this, ts, vk,false, false );
if(ts == true)
gl.keyPressed(event);
else if(ts == false)
gl.keyReleased(event);
}

void mouseMoved(int cord_x, int cord_y, GlobalEventListener gl)
{
//MouseEvent event = new MouseEvent( this, cord_x, cord_y);
//gl.mouseMoved(event);
}

native void registerHook(GlobalEventListener gl);
native void unRegisterHook();


}



jni_SysHook.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class jni_SysHook */

#ifndef _Included_jni_SysHook
#define _Included_jni_SysHook
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jni_SysHook
* Method: registerHook
* Signature: (Ljni/GlobalEventListener;)V
*/
JNIEXPORT void JNICALL Java_jni_SysHook_registerHook
(JNIEnv *, jobject, jobject);

/*
* Class: jni_SysHook
* Method: unRegisterHook
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_jni_SysHook_unRegisterHook
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif



SysHook.cpp
#include <windows.h>
#include <WinUser.h>
#include "SysHook.h"
#include "jni_SysHook.h"
#include "jni.h"

#ifndef WINVER
#define WINVER 0x0500
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif

#if (_WIN32_WINNT >= 0x0400)
#define WH_KEYBOARD_LL 13
#define WH_MOUSE_LL 14
#endif // (_WIN32_WINNT >= 0x0400)

typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode; // virtual key code
DWORD scanCode; // scan code
DWORD flags; // flags
DWORD time; // time stamp for this message
DWORD dwExtraInfo; // extra info from the driver or keybd_event
}KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

HINSTANCE hInst = NULL;

JavaVM * jvm = NULL;
jobject hookObj_kb = NULL;
jobject hookObj_ms = NULL;
jobject g_kl = NULL;

jmethodID processKeyID_kb = NULL;
jmethodID processKeyID_ms = NULL;
DWORD hookThreadId = 0;

LONG g_mouseLocX = -1; // x-location of mouse position
LONG g_mouseLocY = -1; // y-location of mouse position

extern "C"
BOOL APIENTRY DllMain(HINSTANCE _hInst, DWORD reason, LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
printf("C++: DllMain - DLL_PROCESS_ATTACH.\n");
hInst = _hInst;
break;
default:
break;
}

return TRUE;
}

LRESULT CALLBACK MouseTracker(int nCode, WPARAM wParam, LPARAM lParam)
{
JNIEnv * env;
KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;

if (jvm->AttachCurrentThread((void **)&env, NULL) >= 0)
{

if (nCode==HC_ACTION)
{
MOUSEHOOKSTRUCT* pStruct = (MOUSEHOOKSTRUCT*)lParam;
if (pStruct->pt.x != g_mouseLocX || pStruct->pt.y != g_mouseLocY)
{
env->CallVoidMethod(hookObj_ms, processKeyID_ms, (jint)pStruct->pt.x,(jint)pStruct->pt.y, g_kl);
g_mouseLocX = pStruct->pt.x;
g_mouseLocY = pStruct->pt.y;
}

}

}
else
{
printf("C++: LowLevelKeyboardProc - Error on the attach current thread.\n");
}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
JNIEnv * env;
KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;

if(jvm->AttachCurrentThread((void **)&env, NULL) >= 0)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)TRUE, p->vkCode,g_kl);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)FALSE, p->vkCode,g_kl);
break;
default:
break;
}
}
else
{
printf("C++: LowLevelKeyboardProc - Error on the attach current thread.\n");
}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}

void MsgLoop()
{
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}

JNIEXPORT void JNICALL Java_jni_SysHook_registerHook(JNIEnv * env, jobject obj,jobject kl)
{
HHOOK hookHandle_ms = SetWindowsHookEx(WH_MOUSE_LL, MouseTracker, hInst, 0);
HHOOK hookHandle_kb = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0);

g_kl = kl;

if (hookHandle_ms == NULL)
{
printf("C++: Java_SysHook_registerKeyHook - Hook failed!\n");
return;
}
else
{
printf("C++: Java_SysHook_registerKeyHook - Hook successful\n");
}

if (hookHandle_kb == NULL)
{
printf("C++: Java_SysHook_registerKeyHook - Hook failed!\n");
return;
}
else
{
printf("C++: Java_SysHook_registerKeyHook - Hook successful\n");
}

hookObj_kb = env->NewGlobalRef(obj);
jclass cls_kb = env->GetObjectClass(hookObj_kb);
processKeyID_kb = env->GetMethodID(cls_kb, "processKey", "(ZILGlobalEventListener;)V");

hookObj_ms = env->NewGlobalRef(obj);
jclass cls_ms = env->GetObjectClass(hookObj_ms);
processKeyID_ms = env->GetMethodID(cls_ms, "mouseMoved", "(IILGlobalEventListener;)V");

env->GetJavaVM(&jvm);
hookThreadId = GetCurrentThreadId();

MsgLoop();

if (!UnhookWindowsHookEx(hookHandle_kb))
{
printf("C++: Java_SysHook_registerKeyHook - Unhook failed\n");
}
else
{
printf("C++: Java_SysHook_registerKeyHook - Unhook successful\n");
}

if (!UnhookWindowsHookEx(hookHandle_ms))
{
printf("C++: Java_SysHook_registerKeyHook - Unhook failed\n");
}
else
{
printf("C++: Java_SysHook_registerKeyHook - Unhook successful\n");
}
}

JNIEXPORT void JNICALL Java_jni_SysHook_unRegisterHook(JNIEnv *env, jobject object)
{
if (hookThreadId == 0)
return;

printf("C++: Java_SysHook_unRegisterKeyHook - call PostThreadMessage.\n");
PostThreadMessage(hookThreadId, WM_QUIT, 0, 0L);
}
...全文
231 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
blackkettle 2012-08-22
  • 打赏
  • 举报
回复
那个博客上好像有人留言说也遇到的同样的情况。

---(摘)



java代码是用的默认包,我可以正常编译和执行(包括C和JAVA代码都可以正常编译和调用)。
但是如果Java代码放在包中实现,就可以正常加载dll,但是截获键盘和鼠标时就会报错。
希望你帮忙看看是什么问题

#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d9acbb5, pid=4004, tid=3276
#
# JRE version: 6.0_19-b04
# Java VM: Java HotSpot(TM) Client VM (16.2-b04 mixed mode, sharing windows-x86 )
# Problematic frame:
# V [jvm.dll+0xfcbb5]
#
# An error report file with more information is saved as:
# F:\work35\KeyHookWithPackage\hs_err_pid4004.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
C++: DllMain – DLL_PROCESS_ATTACH.
C++: Java_SysHook_registerKeyHook – Hook successful
BadPattern 2012-08-22
  • 打赏
  • 举报
回复
改成指定包没关系,因为我看到你的native方法相应的也变成了:
Java_jni_SysHook_registerHook

Java_jni_SysHook_unRegisterHook

按照jni的规则是可以映射上的,还是要你在这两个方法中加点Log打印或者加个断点看看执行如何
blackkettle 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

这。。。代码太多,而且没有调试环境很难定位问题啊,JVM挂掉很可能因为dll库写的有问题,你多加Log跟踪一下看看哪里代码没执行到
[/Quote]

dr8737010,

您帮我看看吧。我是在这里找到源码的。
http://dengpeng.sensorapp.net/?p=495

源码是在 默认包下的,可以执行没有问题。

我想改写成指定包下。可是就出了问题。

万分感谢!
BadPattern 2012-08-22
  • 打赏
  • 举报
回复
这。。。代码太多,而且没有调试环境很难定位问题啊,JVM挂掉很可能因为dll库写的有问题,你多加Log跟踪一下看看哪里代码没执行到
blackkettle 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

引用 6 楼 的回复:

dr8737010,

你太厉害了!!!搞定了!

我问了好多搞 java的同学,他们几乎都没有搞过 jni,都解答不了这个问题。

万分感谢!!!

呵呵,那就结帖给分吧
[/Quote]

那是必须的。
BadPattern 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

dr8737010,

你太厉害了!!!搞定了!

我问了好多搞 java的同学,他们几乎都没有搞过 jni,都解答不了这个问题。

万分感谢!!!
[/Quote]
呵呵,那就结帖给分吧
blackkettle 2012-08-22
  • 打赏
  • 举报
回复
dr8737010,

你太厉害了!!!搞定了!

我问了好多搞 java的同学,他们几乎都没有搞过 jni,都解答不了这个问题。

万分感谢!!!
BadPattern 2012-08-22
  • 打赏
  • 举报
回复
问题我想应该找到了:
这两行:
processKeyID_kb = env->GetMethodID(cls_kb, "processKey", "(ZILGlobalEventListener;)V");

processKeyID_ms = env->GetMethodID(cls_ms, "mouseMoved", "(IILGlobalEventListener;)V");

得到的processKeyID_kb和processKeyID_ms应该为NULL,你可以打印看看,之后调用CallVoidMethod肯定会空指针.
(ZILGlobalEventListener;)V应该是全限定性名称:(ZILjni/GlobalEventListener;)V

(IILGlobalEventListener;)V同样的应该改为(IILjni/GlobalEventListener;)V

你试试看

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧