`
文昌平蓝杰
  • 浏览: 56254 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

手把手教你实现Java监听器全局监控

阅读更多

 (一) 动态链接库初入门

    1.前段时间,闲来无聊,想做个像QQ截图一样的截图工具,在却在做的过程中发现java自带API中的监听器带有很大的局限性,java的鼠标监听器只有在鼠标在程序窗口之上时才会生效,而键盘监听器则更加局限,只有在当前窗口为焦点窗口时才会生效,这显然是不符合我们需要效果的,我们所需要的是全局的键盘监听,不管你在干什么,只要触发我们设定的固定的组合键是,就会执行我们需要的功能,所以用java是不太好办。

    2.那么QQ是怎么做到的呢?QQ是用C语言写的,并不是java,而且windows也是C语言写出来的,所以他能轻易的实现这种全局监听。这也就是一个突破口,native,不知道你有没有注意过这个关键字,这是用来调用本地代码的一个关键字。我们可以这样设想,假如我们将所有的代码全部用java实现,却用C语言去监听全局键盘,然后返回为我们所用。是不是很有意思。

     首先,我说一说整体的思路,由于java中监听器的局限性,我们将用C语言的HHOOK消息钩子,来获取到全局消息的监听,然后通过jni技术,用java调用,于是就形成java监听器的全局监控。

    3.下面我来说明这样用java代码调用C语言的方法(函数)。

package test;
public class HelloWorld{
         static{
                 System.loadLibrary("HelloDll");
         }  
         public static void main(String args[]){
                 HelloWorld hw = new HelloWorld();
                 hw.sayHello();
         }
         public native void sayHello();
}

       上面这个System.loadLibrary("HelloDll");此句为引入一个叫做HelloDll的本地文件,而这个必定包含了sayHello();的实现代码。java工作我们算是昨晚了,也就是一个简单的打印HelloWorld的代码,重要的是我们怎样用C语言去实现这个本地方法,怎样让其经行工作。

       (1).编写java文件。上一步已经实现

       (2).javac运行源文件生成class文件

       (3).javah test.HelloWorld 这里注意不用上带后缀,我在经行这一步骤时,路径问题很麻烦。在包这一层运行javah test.HelloWorld就会生成一个叫test_HelloWorld.h的C语言头文件。

    因为我们的方法是要用C语言实现的,所以经行到这一步,我们得到了一个C的头文件。如果你打开这个头文件,你会发现里面会有一个叫做JNIEXPORT void JNICALL Java_test_HelloWorld_sayHello(JNIEnv *, jobject);的方法,这个方法其实就是我们的java方法在C语言里边的映射了(我一般这么称呼,不知道对不对),我们只要将这个方法用C语言实现了,然后编译成一个java能调用的DLL本地文件就OK了。

       (4)打开Microsoft Visual C++,File-->new-->Win32 Dynamic-Link Library,新建一个叫HelloDLL的文件动态链接工程,点击左下角FileView,点开HelloDll files。然后File-->new-->C/C++ Header File,名字为test_HelloWorld.h,然后点开Header Files里的test_HelloWorld.h,将我们刚才生成的test_HelloWorld.h文件内容复制进去,再File-->new-->C++ Source File,名字hello(随便取),然后点开文件写入内容:

#include "test_HelloWorld.h"
#include <iostream.h>
JNIEXPORT void JNICALL Java_test_HelloWorld_sayHello
    (JNIEnv *, jobject){
		cout<<"HelloWorld"<<endl;
}

       可以看出,我们生成头文件的目的,无非就是为了用C语言实现,因为我们这里引入了这个头文件,而这里边唯一的一个方法,就是我们生成的头文件,也就是我们的java代码未实现的代码在C中的映射,然后我在这个方法中打印了HelloWorld这句话。(如果看不懂C代码,建议百度一下,就算看不懂,凭我文字描述应该也是能懂一些的,不过应该不会看不懂吧)。

 

       另外就是,这一个段落我写的比较详细,甚至比较啰嗦,主要是为了没用过Microsoft Visual C++或者没学过C的人,能够手把手的教他运行这个程序,大神可以略过。

       好了,言归正传,我们还需引入java的lib环境,Tools-->Options-->Directories在底下的方框栏中加入你C:\PROGRAM FILES\JAVA\JDK1.6.0_04\INCLUDE和C:\PROGRAMFILES\JAVA\JDK1.6.0_04\INCLUDE\WIN32也就是java的JDK的include和include中win32两个文件夹。然后Build-->Rebuild All。

       你会发现,在你C++文件夹HelloDll中Debug中有一个HelloDll.dll文件。那么这个文件就是我们需要的动态链接文件了。如果你将它打开,那么你会发现大部分是乱码。

    (5)将得到的HelloDll.dll复制到你的java工程的包这一层下,然后运行java test.eHelloWorld,就会打印HelloWorld这句话了,如果在没有这个dll文件时你就引进运行了,会抛出一个找不到动态链接文件的异常。

    (6)这样我们就实现了用java调用C语言的方法了。这就是动态链接了,在下一篇我将描述,怎样用C语言的HHOOK钩子去获取windows底层键盘和鼠标的相应。

 (二)怎样用C语言获取全局消息HHOOK

     国际惯例,我先说一说这一章的思路,这一章主要是讲Windows API中两个钩子函数,加上一些窗口处理。首先我利用API创建窗体,窗体消息交由WindowProc(自定义)去处理,在窗体创建时设置全局钩子,在窗体销毁时去除钩子,而在钩子内部,通过keyLisProc和mouseLisProc去处理钩子获取到的消息,

当钩子获取到鼠标或键盘时,赋予全局变量keyCode或mouseCode,最后通过javah生成的函数返回给java动态链接,实现java的jni全局监控

    (1)在Windows的API中,有这么一个函数

HHOOK WINAPI SetWindowsHookEx( int idHook, HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThread)
这个函数的第一个参数是代表钩子的类型,例如WH_KEYBOARD_LL代表的是键盘键监听,WH_MOUSE_LL代表的是鼠标的监听,第二个参数代表的是钩子函数的地址指针,也就是将交由那个函数去处理这个事件,类似于监听器的作用(但不是),第三个代表应用程序实例的句柄,第四个为与程序相关的线程的ID,如果为0,即为全局监控
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
    switch ( msg ) {
	//当窗体创建的时候
         case WM_CREATE:
	//将系统钩子设置
             hKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyLisProc, all_hInst, 0);
             hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseLisProc, all_hInst, 0);
           break;
          //当窗体清除的时候
        case WM_DESTROY:
	//如果消息钩子已经设置
             if ( hKeyHook != NULL && hMouseHook != NULL ) {
	 //清除消息钩子
                 UnhookWindowsHookEx(hKeyHook);
                        UnhookWindowsHookEx(hMouseHook);
	}
	//向系统发送关闭信息
             PostQuitMessage(0);
             break;
       default:
             return DefWindowProc(hwnd, msg, wparam, lparam);
   }
    return 0;
}
 这就是windows在窗口消息中的响应方法,他规定了在窗体创建时设置钩子,窗体消失时取消钩子。而钩子设置成功后,可以看到是由一个叫keyLisProc的函数去处理消息的
LRESULT CALLBACK keyLisProc(int nCode, WPARAM wParam, LPARAM lParam) {
   //存储按键信息的结构体
   KBDLLHOOKSTRUCT* KeyInfo = NULL;
   //如果按下了
   if ( nCode >= 0 && wParam == WM_KEYDOWN ) {
    KeyInfo = (KBDLLHOOKSTRUCT*)lParam;
	//获取到结构体中按键的KeyCode值
    keyCode = KeyInfo->vkCode;
   }
   return CallNextHookEx(NULL, nCode, wParam, lParam);
}
 这个就是那个消息处理,首先将获取到键盘信息,存储到KeyInfo结构体中,然后从中取出来付给KeyCode,而keyCode是一个全局变量,我们只需要在javah时生成的函数中,返回给java代码就可以了,是不是相对来说,有点复杂了,但事实上思路很清晰,只要多分析,就不会太难理解。    
     注意:在VC6.0中引入winuser.h是没有用的,需要用的结构体和宏定义得自己添加
#define WH_KEYBOARD_LL     13
#define WH_MOUSE_LL        14
typedef struct tagMSLLHOOKSTRUCT {
    POINT   pt;
    DWORD   mouseData;
    DWORD   flags;
    DWORD   time;
    DWORD   dwExtraInfo;
} MSLLHOOKSTRUCT, FAR *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
typedef struct tagKBDLLHOOKSTRUCT {
    DWORD   vkCode;
    DWORD   scanCode;
    DWORD   flags;
    DWORD   time;
    DWORD   dwExtraInfo;
} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
 在C语言这一块,我只是讲解了很多思路,因为你如果不会这门 语言,我真的没有办法在这里教会你,这是一个比较难以表达的事情,如果你真的很想搞懂,987706386是我的QQ,其实我思路已经说得比较明了,加上下载我上传的文档看一看,那就很容易理解。
        好了,把我上传的代码试一试,然后自己研究研究,加上自己的理解,我想不难理解这种思路,这样一来就解决的java全局监控的问题,是不是?(可以先看文档,比较容易,因为博客上文档不齐全。)
那么其实我所要解说的内容,基本完毕,这一篇博客也就基本说清楚了,还有不清楚,上面的QQ,还有就是QQ截图,我还在慢慢更新界面,也许一时半会,还木有成品,如果做出来了,将会在另一篇博客中给大家呈现。谢谢
 
5
2
分享到:
评论
10 楼 在世界的中心呼喚愛 2013-05-25  
不错。。曾经面试被问倒jni。没有答出来。。
9 楼 文昌平蓝杰 2013-05-18  
博客已更新完成,欢迎大家一起讨论
8 楼 文昌平蓝杰 2013-05-17  
我是楼主。没有,我觉得要实现这种全局监控,必须得学会jni技术,不然就不会调用C语言的代码,那有怎么实现全局监控呢
7 楼 bewithme 2013-05-16  
楼主快说正题呀
6 楼 david_je 2013-05-16  
感觉是在讲JNI在入门,没有提到和标题相关的东西啊
5 楼 ileson 2013-05-15  
学习入门 不错。不过这个不可能要求用户为了你的软件,还要装一个jdk .
学习笔记 值得鼓励。。。
4 楼 steafler 2013-05-15  
楼主此文就是想介绍下如何玩java native吧
3 楼 hbbbs 2013-05-15  
哈,最好能在最上面介绍下思路,也让读者们迅速掌握关键信息。

直接在题目上写明:JNI实现全局监控
2 楼 lohasle 2013-05-15  
jni   jna  jnative
1 楼 瓶鱼跃 2013-05-14  
实际上这样的需求在工作中应该很少吧!

相关推荐

    手把手教你学DSP:基于TMS320F28335

    手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F...

    手把手教你学dsp2812,手把手教你学dsp2812pdf下载,C,C++

    《手把手教你学DSP2812》是一本专为初学者设计的 DSP(Digital Signal Processor)学习指南,主要围绕TI公司的TMS320F2812 DSP芯片进行讲解。这本书以其全面且易懂的特性,为读者提供了一个深入理解数字信号处理及其...

    手把手教你学28335

    手把手教你学28335PDF文档,看了这个确实和2812有了对比

    手把手教你开发java手机程序

    在"手把手教你开发java手机程序"的教程中,你可能会学习到以下几个核心知识点: 1. **环境配置**:开始Java开发前,你需要安装Java Development Kit (JDK) 和Android Studio,这是Android开发的官方集成开发环境...

    手把手教你学DSPPDF

    【标题】"手把手教你学DSPPDF"是一份针对数字信号处理(DSP)初学者的教程性PDF文档,旨在引领读者逐步掌握这一领域的基础知识。该文档可能包含了从理论概念到实际应用的全面讲解,适合那些希望踏入数字信号处理世界...

    手把手教你学DSP28335

    手把手教你学DSP28335,PDF格式,有助于随时随地可以学习知识。

    手把手教你dsp28335,高清pdf

    手把手教你学DSP28335高清pdf文件,北京航空航天大学出版社

    手把手教你实现第一个SSH项目

    ssh 项目 创建 教程 手把手教你实现第一个SSH项目

    手把手教你学dsp

    手把手教你学dsp F2812 顾伟刚

    手把手教你如何从一无所有到财务自由.pdf

    "手把手教你如何从一无所有到财务自由.pdf" 本文主要讲述的是如何从零开始创业,到达财务自由的三个步骤。作者通过幽默诙谐的语言,浅显易懂的思维高度,指导小屁孩创业,并提供了非常好的指引方向。 第一部分:...

    手把手教你打造apk安装器

    【标题】"手把手教你打造apk安装器"的教程涵盖了创建和使用自定义APK安装程序的核心技术。在Android平台上,APK是应用程序的二进制格式,通常通过Google Play或其他应用商店进行分发。然而,有时候我们可能需要创建...

    手把手教你实现一个Java Agent.pdf

    Java Agent是一种强大的技术,它允许我们在程序运行时对字节码进行修改,从而实现无侵入式的监控、性能分析和代码增强等功能。本教程将引导你一步步实现一个简单的Java Agent。 首先,我们要理解Java Agent的核心...

    《手把手教你学51单片机》教材pdf

    《手把手教你学51单片机》教材的出版,对于那些渴望踏入嵌入式开发领域的初学者而言,无疑是一份难得的珍藏资料。51单片机作为微控制器的经典代表,一直占据着嵌入式系统教学和应用的前沿,其地位不可动摇。本书以51...

    003《老HRD手把手教你做绩效考核》.pdf

    003《老HRD手把手教你做绩效考核》.pdf

    手把手教你DSP配套资料

    “手把手教你DSP配套资料”这一压缩包很可能是包含了一系列关于DSP的学习材料,可能包括教程文档、示例代码、实验指导等。通过这些资料,你可以深入理解DSP的基本原理、算法和应用,逐步掌握实际操作技能,为你的...

    《手把手教你学dsp2812》顾卫刚.PDF

    根据给出的文件信息,《手把手教你学dsp2812》是顾卫刚所著的一本关于DSP2812的教材书籍。DSP2812指的是德州仪器(Texas Instruments,简称TI)的TMS320F2812数字信号处理器。TMS320F2812是一款32位的高性能数字信号...

    手把手教你学51单片机C语言版PDF

    《手把手教你学51单片机C语言版》是一本专为初学者设计的教程,旨在帮助读者从零开始掌握51系列单片机的编程与应用。这本书由权威的电子技术教育平台www.kingst.org提供,是学习单片机C语言编程的宝贵资源。下面将...

Global site tag (gtag.js) - Google Analytics