【问题标题】:cannot see the message when user presses the key用户按键时看不到消息
【发布时间】:2012-05-24 04:29:58
【问题描述】:

以下java 程序调用C 中的本机方法,如果用户按下某个键,该方法应打印一条消息you pressed a key !。但是当我按下键时我看不到消息。我还检查函数SetWindowsHookEx是否返回null,但不是,它不返回null。

Java 代码:

package keylogger;

public class TestKeys {

private native void setWinHook();

public static void main(String args[]) {
    TestKeys o = new TestKeys();
    try {
        o.setWinHook();
        Thread.sleep(10000);
    } catch(Exception exc) {
        exc.printStackTrace();
    }
}

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 LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
  printf("You pressed a key !\n");
  return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}

void Java_keylogger_TestKeys_setWinHook
 (JNIEnv *env, jobject obj) {
hInst = GetModuleHandle(NULL); // include or exclude,i don't see the result
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,NULL, 0);
if(handleKeyboardHook==NULL) {
    printf("Is Null");
} else {
    printf("Is not Null");
}
printf("Inside fucntion setWinHook !");
}

/*int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 printf("Hello World !");
 handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
 if(handleKeyboardHook==NULL) {
  printf("Is Null");
 } else {
    printf("Is not Null");
   }
 MSG msg;
 while(GetMessage(&msg, NULL, 0, 0))
 {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
 }
 return msg.wParam;
}*/

我看到的唯一输出是 Is not NullInside fucntion setWinHook !

问题出在哪里?

我应该怎么做才能让这个程序在我按下键时返回消息。 我看到的唯一输出是:Inside function setWinHook !

注意:

如果上面的程序在别人的机器上运行,请注明。

输出图片:

我在按键时没有看到任何消息。程序仅在 10 秒后退出而不显示消息。

【问题讨论】:

标签: java c winapi java-native-interface keylogger


【解决方案1】:

您不能简单地声明一个本地 HINSTANCE 变量并将其传递给函数。 HINSTANCE 是应用程序实例的句柄,换句话说,是一个必须指向有效位置的指针。您需要使用属于您自己的应用程序的 HINSTANCE。

我的 Windows API 有点生疏,但我相信您可以通过 GetModuleHandle() 来做到这一点。 所以:

void Java_keylogger_TestKeys_setWinHook
     (JNIEnv *env, jobject obj) {
   HINSTANCE hInst;
   hInst = GetModuleHandle(null);
   handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0);
   printf("Inside function setWinHook !");
 }

您的 Java goo 也很可能在某个对象中隐藏了 HINSTANCE。

【讨论】:

  • 你能解释一下“你的Java goo也很可能在某个对象中隐藏了一个HINSTANCE。”
  • @SuhailGupta 你知道 HINSTANCE 做什么吗?它是所有 Windows API 程序中使用的一个非常基本的句柄。如果您不知道它的作用,则不应尝试键盘挂钩等高级机制。我强烈推荐 Charles Petzold 的《Programming Windows》一书,非常好的书,非正式地称为 Windows API 圣经。
  • 虽然我不知道窗口句柄,但我知道窗口调用了SetWindowsHookEx指向的方法。在这种情况下LowLevelKeyboardProc。我肯定会学习 Windows API,但我想运行这个程序!
  • @SuhailGupta 好吧,它不起作用,因为你没有给钩子过程一个有效的句柄(HINSTANCE)到你的应用程序。你需要从某个地方得到这个。如果 GetModuleHandle() 不起作用,也许其他阅读本文的人(对 Windows API 不那么生疏)可以指出获取 HINSTACE 的最简单方法? (一种确定可行的方法是从 WM_CREATE 调用 SetWindowsHookEx,然后通过 LPARAM 在结构中将 HINSTANCE 传递给您。)
  • 顺便说一句,当程序完成时,您还需要从某个地方调用 UnhookWindowsHookEx() 进行清理。
【解决方案2】:

查看Java Global(low level) Keyboard/Mouse Hook

我尝试自己写一个,但对我来说似乎有太多未知的细节(JNI、HOOKS、线程问题等)

【讨论】:

    【解决方案3】:

    HHOOK 变量需要在共享数据段内声明。 在这里检查它是如何完成的 - http://www.codeproject.com/Articles/5002/Mousey-Roll-Over-and-Park

    【讨论】:

      【解决方案4】:

      您需要一个GetMessage/PeekMessage 循环,以便您的键盘挂钩接收任何事件。有关 Windows 上键盘挂钩的 Java 实现,请参阅JNA Keyboard Hook in Windows,或在 JNA 项目中执行相同功能的贡献包 (https://github.com/twall/jna/tree/master/contrib/w32keyhook)。

      【讨论】:

        【解决方案5】:

        肯定有更好的方法来实现这一点。这里DllMain 在创建线程后被多次调用,这对我来说似乎不对。我不确定这是否合法! C 代码启动一个新线程来实现 keycatcher。

        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 int i = 0;
        
        static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
        
          printf("You pressed the key !");
          return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
        }
        
        
        BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
         if(hookThreadHandle==NULL) {
            printf("hookThreadHandle is NULL\n");
            LPTHREAD_START_ROUTINE lpStartAddress = &installHook;
            hookThreadHandle = CreateThread(NULL, 0, lpStartAddress, NULL, 0, &hookThreadId);
         }
        }
        
        BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) {
        // printf("From installHook : %u",fwdReason);
        printf("count : %d\n",i++);
        handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstDLL, 0);
        MSG msg;
        
        while(GetMessage(&msg, NULL, 0, 0))
        {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        }
        return msg.wParam;
        }
        
        void Java_keylogger_TestKeys_unregisterWinHook
         (JNIEnv *env, jobject obj) {
         // should have stopped the thread before unhooking
         if(handleKeyboardHook != NULL) {
            UnhookWindowsHookEx(handleKeyboardHook);
         }
        }
        
        void Java_keylogger_TestKeys_stopNativeThread // stop the native thread
          (JNIEnv *env, jobject obj) {
            PostThreadMessage(hookThreadId, WM_QUIT, (WPARAM) NULL, (LPARAM) NULL);
            WaitForSingleObject(hookThreadHandle, 5000);
        }
        

        Java 代码:

        package keylogger;
        
        public class TestKeys {
        private static int i = 0;
        private native void setWinHook();
        private native void unregisterWinHook();
        private native void createWinThread();
        private native void stopNativeThread();
        
        public static void main(String args[]) {
            TestKeys o = new TestKeys();
            try {
                Thread.sleep(5000);
            }catch(Exception exc) {
                exc.printStackTrace();
            }
           o.stopNativeThread();
           o.unregisterWinHook();
           System.out.println("Native thread stopped and Hook unregistered !");
        
           try {
                Thread.sleep(3000); // Now you won't see the message : you pressed the key 
            }catch(Exception exc) {
                exc.printStackTrace();
            }
        }
        
        static {
            System.loadLibrary("MyHook");
        }
        }
        

        我启动java程序并调用DLLMain

        【讨论】:

        • 好吧,你不应该以这种方式使用 DllMain,但如果你的答案有效,我猜你的代码中缺少的是消息循环while(GetMessage(&amp;msg, NULL, 0, 0)) ...,所以也许你应该在代码中使用一个您在问题中写道。
        • @paercebal 有没有更好的方法来实现这一目标?如果有,请在单独的答案中提及。
        猜你喜欢
        • 1970-01-01
        • 2011-04-13
        • 2011-01-29
        • 1970-01-01
        • 1970-01-01
        • 2015-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多