WINAPI消息循环让我发疯

时间:2012-04-06 14:58:19

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

我一直在尝试使用JNI实现简单的低级别keyhook并且一切顺利,直到我认为当DLL处于无限循环(消息循环)时我无法调用这些方法。所以我决定创建新的线程,但不知何故,在我做了它之后,消息循环在它自己的循环上运行,低级别keyhook停止响应意味着它不再调用keyproc,我不知道为什么会这样?这有什么其他的工作吗?我需要能够在键盘挂钩仍在运行时调用DLL的方法。

我目前的代码就像

一样简单

注册键盘钩子:

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);
}

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

2 个答案:

答案 0 :(得分:2)

您需要在调用SetWindowsHookEx()的同一线程上抽取消息循环。所以只需将调用移到ThreadProc()即可。当然,请注意您的CallVoidMethod()回调也在同一个线程上运行,因此请小心您在该函数中执行的操作。您访问的任何共享状态都需要使用锁保护。

答案 1 :(得分:1)

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

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