java - 一个函数多次调用 : why ? 以及通过 C 线程使用不当?

标签 java c multithreading winapi java-native-interface

通过以下代码,我尝试实现一个简单的击键捕捉器。当用户点击某个键时,他会收到通知。 Java 代码加载 dll运行 DllMain方法也从中启动一个新线程。`

Java 代码在静态 block 中加载库。dllDllMain执行并打印一些语句的方法。它还从DllMain启动一个新线程。 。 java 程序中还启动了一个新线程,该线程 hibernate 2 毫秒。从输出看来 DllMain , installHook被多次调用。这是为什么 ?有什么问题吗?

虽然点击按键时会通知用户,但为什么同一函数会被多次调用?我想我已经实现了功能 installHook或者以糟糕的方式实现线程逻辑。

Java 代码:

package keylogger;

public class TestKeys {
private static int i = 0;
private native void setWinHook();
private native void unregisterWinHook();

public static void main(String args[]) {

    //TestKeys o = new TestKeys();


    System.out.println("After the call to load library !");

    Runnable r = new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println("Sleeping...");
                Thread.sleep(2);
            }catch(Exception exc) {
                exc.printStackTrace();
            }
        }
    };
    new Thread(r,"new thread").start();       
}

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

C 代码:

#include <stdio.h>
#include <windows.h>
#include <w32api.h>
#include "keylogger_TestKeys.h"

static HHOOK handleKeyboardHook = NULL;
HINSTANCE hInst = NULL;
static DWORD hookThreadId = 0;
static HANDLE hookThreadHandle = NULL;
BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved);

static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
 printf("You pressed the key !\n");
 return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) {
  LPTHREAD_START_ROUTINE lpStartAddress = &installHook;
  printf("From DllMain : %u\n",fwdReason);
  hookThreadHandle = CreateThread(NULL, 0, lpStartAddress, NULL, 0, &hookThreadId);
  if(hookThreadHandle == NULL) {
    printf("\nhookThreadHandle is NULL\n");
  }
  return TRUE;
}

JNIEXPORT void JNICALL Java_keylogger_TestKeys_unregisterWinHook
 (JNIEnv *env, jobject obj) {
   if(handleKeyboardHook != NULL) {
    UnhookWindowsHookEx(handleKeyboardHook);
    printf("Keyboard hook successfully unregistered !");
   } else {
      printf("Coudn't Unhook the keyboard hook !");
     }
} 

BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) {
printf("From installHook : %u",fwdReason);
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstDLL, 0);
MSG msg;

while(GetMessage(&msg, NULL, 0, 0))
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}
return msg.wParam;

}

输出:

From DllMain : 1
From DllMain : 2
From installHook : 66321916From DllMain : 2
After the call to load library !From installHook : 65797624
From DllMain : 2
From installHook : 67304108From DllMain : 2
From installHook : 60423404From DllMain : 2
From installHook : 67893304From DllMain : 2
From installHook : 68484828From DllMain : 2
From installHook : 69204012From DllMain : 2 
From installHook : 61799988From DllMain : 2
From installHook : 62847812From DllMain : 2
From DllMain : 2
Sleeping... 
From installHook : 71695184From DllMain : 2
From installHook : 70907884From DllMain : 2
From installHook : 70581032From DllMain : 2
From installHook : 72219984From DllMain : 2
From installHook : 73071020From DllMain : 2
From installHook : 66649544From DllMain : 2
From installHook : 73399648From DllMain : 3
From DllMain : 2
From DllMain : 3
From installHook : 73858604From DllMain : 2
From DllMain : 3
From installHook : 75955548From DllMain : 3
From DllMain : 2
From installHook : 72548100From DllMain : 2
From installHook : 74643796From DllMain : 2
From installHook : 75560952From DllMain : 3
From DllMain : 2
From installHook : 71236420From DllMain : 2
From installHook : 74316888From DllMain : 2
From installHook : 77265476From DllMain : 0

hookThreadHandle is NULL

最佳答案

来自DllMain文档:

An optional entry point into a dynamic-link library (DLL). When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. The system also calls the entry-point function for a DLL when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.

由于您在该函数中创建了一个线程,因此实际上存在一个无限循环 - DllMain(加载时)创建了一个线程,因此 DllMain 是调用,启动一个线程,因此调用 DllMain ...

请仔细阅读该文档,如果原因不是 DLL_PROCESS_ATTACH (1),您可能不应该执行任何操作。 (我实际上不确定从该过程启动线程是否合法。)

关于java - 一个函数多次调用 : why ? 以及通过 C 线程使用不当?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10815827/

相关文章:

java - 如何加载 Spring 中 conf 或 resources 目录下的任何文件

c - 使用正则表达式解析以分号分隔的字符串

c++ - 如何使用 dlmopen 在不同线程中打开多个共享库?

java - 让线程 hibernate 的更好方法

python - 在除发送者之外的所有线程上使用 Python 发送单向消息

java - 如果 Java 字符串是不可变的而 StringBuilder 是可变的,为什么它们在我的代码中浪费了相同数量的内存?

java - 无法与远程机器上的 MySQL 数据库建立连接

java - 将线程与 paint java 一起使用

java - 运行单元测试时无法从 KeyStore 读取证书

c - 在 C 中返回 int 数组