2012-04-06 76 views
0

我一直试图使用JNI实现简单的低级别keyhook,一切都很顺利我想我无法在DLL在无限循环(消息循环)时调用方法。所以我决定创建新的线程,但不知何故,我做了它之后,消息循环运行在它自己的循环中,低级别keyhook停止响应,意味着它不再调用keyproc,我不知道这是为什么?有没有其他的解决方法呢?我需要能够在键盘挂钩仍在运行时调用DLL的方法。WINAPI的消息循环驱使我疯狂

我当前的代码很简单,只要

寄存器键盘钩子:

keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProc, hInstance, 0); 

启动线程

HANDLE threadHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadId); 

我的键盘proc和ThreadProc的有以下几种:

DWORD WINAPI ThreadProc(LPVOID lpVoid) { 
    MSG msg; 
    while(GetMessage(&msg, NULL, 0, 0)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
    return 0; 
} 

LRESULT CALLBACK keyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { 
    KBDLLHOOKSTRUCT keyEvent = *((KBDLLHOOKSTRUCT*)lParam); 
    jint vkCode = keyEvent.vkCode; 
    jint flags = keyEvent.flags; 
    jint action = wParam; 
    (*globalEnv).CallVoidMethod(globalObj, keyboardMethodId, vkCode, flags, action); 
    return CallNextHookEx(NULL, nCode, wParam, lParam); 
} 

我该在哪里出错? 即使我为从未调用的keyproc添加简单日志记录,我也确信它不是java。但是,如果我停止使用线程并在主线程上运行消息循环,它将正常工作,但DLL不会响应之后的方法调用。

+0

http://stackoverflow.com/questions/617248/can-the-hwnd-from-createwindow-createdialog-be-getmessaged-from-another-thread – JosephH 2012-04-06 15:05:59

回答

2

您需要在调用SetWindowsHookEx()的同一个线程上抽取消息循环。所以把这个调用移动到你的ThreadProc()。当然,要注意你的CallVoidMethod()回调函数在同一个线程上运行,所以要小心你在那个函数中做了什么。您访问的任何共享状态都需要使用锁来保护。

+0

你在那里提出了一些有效的观点。我会在那里打电话试试看!锁只是为了确保两个线程没有并发访问来搞乱一些数据? – Ruuhkis 2012-04-06 15:25:01

+0

谢谢,你解决了我的问题! :) – Ruuhkis 2012-04-06 15:34:35

1

您正在尝试安装跨桌面所有进程的桌面范围挂钩。也就是说,您的DLL被映射到几个具有特定进程集的全局变量的进程。您在其他进程中没有有效的globalEnv,并且您可能会遇到访问冲突或类似错误(全局变量可以使用共享数据段创建,请参阅this article for details)。

要安装线程特定的钩子,您需要一个不同类型的钩子(WH_KEYBOARD_LL是全局唯一的!)和SetWindowsHookEx中的非零最后一个参数。

+0

这正是我想要的,我需要dektop宽挂钩附加快捷键等,它运作良好,直到我试图运行外部线程上的消息循环,它甚至有可能吗?我只需要在挂钩后能够响应我的方法调用。 – Ruuhkis 2012-04-06 15:10:45

+0

那么你的'globalEnv'是什么? – 2012-04-06 15:14:55

+0

Java环境对象:P – Ruuhkis 2012-04-06 15:24:01