深入浅出HOOKS

 深入浅出HOOKS(上)

      
HOOKS 说明书

hook是WINDOWS提供的一种消息处理机制,它使得程序员可以使用子过程来监视系统消息,并在消息到达目标过程前得到处理。

下面将介绍WINNDOWS HOOKS并且说明如何在WINDOWS 程序中使用它。

使用HOOK 将会降低系统效率,因为它增加了系统处量消息的工作量。建议在必要时才使用HOOK,并在消息处理完成后立即移去该HOOK。

HOOK链

WINDOWS提供了几种不同类型的HOOKS;不同的HOOK可以处理不同的消息。例如,WH_MOUSE HOOK用来监视鼠标消息。

WINDOWS为这几种HOOKS维护着各自的HOOK链。HOOK链是一个由应用程序定义的回调函数队列,当某种类型的消息发生时,WINDOWS向此种类型的HOOK链的第一个函数发送该消息,在第一函数处理完该消息后由该函数向链表中的下一个函数传递消息,依次向下。如果链中某个函数没有向下传送该消息,那么链表中后面的函数将得不到此消息。(对于某些类型的HOOK,不管HOOK链中的函数是否向下传递消息,与此类型HOOK联系的所有HOOK函数都会收到系统发送的消息)

 

===========================HOOK过程========================

为了拦截特定的消息,你可以使用SetWindowsHookEx函数在该类型的HOOK链中安装你自己的HOOK函数。该函数语法如下:

public function MyHook(nCode,wParam,iParam) as long

‘加入代码

end function

其中MyHook可以随便命名,其它不能变。该函数必须放在模块段。nCode指定HOOK类型。wParam,iParam的取值随nCode不同而不同,它代表了某种类型的HOOK的某个特定的动作。

SetWindowsHookEx总是将你的HOOK函数放置在HOOK链的顶端。你可以使用CallNextHookEx函数将系统消息传递给HOOK链中的下一个函数。

[注释]对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时,HOOK函数中的CallNextHookEx语句将被忽略。

全局HOOK函数可以拦截系统中所有线程的某个特定的消息(此时该HOOK函数必须放置在DLL中),局部HOOK函数可以拦截指定线程的某特定消息(此时该HOOK函数可以放置在DLL中,也可以放置在应用程序的模块段)。

[注释] 建议只在调试时使用全局HOOK函数。全局HOOK函数将降低系统效率,并且会同其它使用该类HOOK的应用程序产生冲突。

 

========================HOOK类型=================================

WH_CALLWNDPROC 和 WH_CALLWNDPROCRET HOOK

WH_CALLWNDPROC 和WH_CALLWNDPROCRET HOOK可以监视SendMessage发送的消息。系统在向窗体过程发送消息前,将调用WH_CALLWNDPROC;在窗体过程处理完该消息后系统将调用WH_CALLWNDPROCRET。

WH_CALLWNDPROCRET HOOK会向HOOK过程传送一个CWPRETSTRUCT结构的地址。该结构包含了窗体过程处理系统消息后的一些信息。

WH_CBT Hook

系统在激活,创建,消毁,最小化,最大化,移动,改变窗体前;在完成一条系统命令前;在从系统消息队列中移去鼠标或键盘事件前;在设置输入焦点前,或同步系统消息队列前,将调用WH_CBT HOOK。你可以在你的HOOK 过程拦截该类HOOK,并返回一个值,告诉系统,是否继续执行上面的操作。

WH_DEBUG HOOK

系统在调用与某种HOOK类型联系的HOOK过程前,将调用WH_DEBUG ,应用程序可以使用该HOOK决定是否让系统执行某种类型的HOOK。

WH_FOREGROUNDIDLE Hook

系统在空闲时调用该HOOK,在后台执行优先权较低的应用程序。

WH_GETMESSAGE Hook

WH_GETMESSAGE Hook使应用程序可以拦截GetMessage 或 PeekMessage的消息。应用程序使用WH_GETMESSAGE HOOK监视鼠标、键盘输入和发送到队列中的其它消息。

WH_JOURNALRECORD Hook

WH_JOURNALRECORD Hook使应用程序可以监视输入事件。典型地,应用程序使用该HOOK记录鼠标、键盘输入事件以供以后回放。该HOOK是全局HOOK,并且不能在指定线程中使用。

WH_JOURNALPLAYBACK Hook

` WH_JOURNALPLAYBACK Hook使应用程序可以向系统消息队列中插入消息。该HOOK可以回放以前由WH_JOURNALRECORD HOOK录制的鼠标、键盘输入事件。在WH_JOURNALPLAYBACK Hook安装到系统时,鼠标、键盘输入事件将被屏蔽。该HOOK同样是一个全局HOOK,不能在指定线程中使用。

WH_JOURNALPLAYBACK Hook返回一个时间暂停值,它告诉系统,在处理当前回放的消息时,系统等待百分之几秒。这使得此HOOK可以控制在回放时的时间事件。

WH_KEYBOARD Hook

WH_KEYBOARD Hook使应用程序可以监视由GetMessage和PeekMessage返回的WM_KEYDOWN 及WM_KEYUP消息。应用程序使用该HOOK监视发送到消息队列中的键盘输入。

WH_MOUSE Hook

WH_MOUSE Hook 使应用程序可以监视由GetMessage和PeekMessage返回的消息。应用程序使用该HOOK监视发送到消息队列中的鼠标输入。

WH_MSGFILTER and WH_SYSMSGFILTER Hooks

WH_MSGFILTER 和WH_SYSMSGFILTER Hooks使应用程序可以监视菜单、滚动条、消息框、对话框,当用户使用ALT+TAB或ALT+ESC来切换窗体时,该HOOK也可以拦截到消息。WH_MSGFILTER仅在应用程序内部监视菜单、滚动条、消息框、对话框,而WH_SYSMSGFILTER则可以在系统内监视所有应用程序的这些事件。

WH_SHELL Hook

一个SHELL程序可以使用WH_SHELL Hook来接收重要的信息。当一个SHELL程序被激活前或当前窗体被创建、消毁时,系统会调用WH_SHELL Hook过程。

 

=======================使用HOOK============================

安装、消毁HOOK过程

监视系统事件

 

安装、消毁HOOK过程

使用SetWindowsHookEx函数,指定一个HOOK类型,自己的HOOK过程是全局还是局部HOOK,同时给出HOOK过程的进入点,就可以轻松的安装你自己的HOOK过程。

为了安装一个全局HOOK过程,必须在应用程序外建立一个DLL,并将该HOOK函数封装到其中,应用程序在安装全局HOOK过程时必须先得到该DLL模块的句柄。将DLL名传递给LoadLibrary 函数,就会得到该DLL模块的句柄;得到该句柄 后,使用GetProcAddress函数可以得到HOOK过程的地址。最后,使用SetWindowsHookEx将HOOK过程的首址嵌入相应的HOOK链中,SetWindowsHookEx传递一个模块句柄,它为HOOK过程的进入点,线程标识符置为0,指出:该HOOK过程同系统中的所有线程关联。

以下是C写的例程,大家可以方便的转换为VB程序。

HOOKPROC hkprcSysMsg;

static HINSTANCE hinstDLL;

static HHOOK hhookSysMsg;

.

.

.

 

hinstDLL = LoadLibrary((LPCTSTR) "c://windows//sysmsg.dll");

hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");

hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER,

hkprcSysMsg, hinstDLL, 0);

 
Hook简介

2000-03-18· -·cww

 

  Hook这个东西有时令人又爱又怕,Hook是用来拦截系统某些信息之用,例如说,我们想 让系统不管在什麽地方只要按个Ctl-B便执行NotePad,或许您会使用Form的KeyPreview,设定为True,但在其他Process中按Ctl-B呢?那就没有用,这时就得设一个Keyboard Hook来拦截所有Key in的键;再如:MouseMove的Event只在该Form或Control上有效,如 果希望在Form的外面也能得知Mouse Move的信息,那只好使用Mouse Hook来栏截Mouse 的信息。再如:您想记录方才使用者的所有键盘动作或Mosue动作,以便录巨集,那就使用JournalRecordHook,如果想停止所有Mosue键盘的动作,而放(执行)巨集,那就使用JournalPlayBack Hook;Hook呢,可以是整个系统为范围(Remote Hook),即其他 Process的动作您也可以拦截,也可以是LocalHook,它的拦截范围只有Process本身。Remote Hook的Hook Function要在.Dll之中,Local Hook则在.Bas中。

在VB如何设定Hook呢?使用SetWindowsHookEx()

 

Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA"(ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long

 

 

idHook代表是何种Hook,有以下几种

Public Const WH_CALLWNDPROC = 4

Public Const WH_CALLWNDPROCRET = 12

Public Const WH_CBT = 5

Public Const WH_DEBUG = 9

Public Const WH_FOREGROUNDIDLE = 11

Public Const WH_GETMESSAGE = 3

Public Const WH_HARDWARE = 8

Public Const WH_JOURNALPLAYBACK = 1

Public Const WH_JOURNALRECORD = 0

Public Const WH_KEYBOARD = 2

Public Const WH_MOUSE = 7

Public Const WH_MSGFILTER = (-1)

Public Const WH_SHELL = 10

Public Const WH_SYSMSGFILTER = 6

 

lpfn代表Hook Function所在的Address,这是一个CallBack Fucnction,当挂上某个Hook时,我们便得定义一个Function来当作某个信息产生时,来处理它的Function,这个Hook Function有一定的参数格式

 

Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long, ByVal lParam As Long ) As Long

 

nCode 代表是什麽请况之下所产生的Hook,随Hook的不同而有不同组的可能值wParam lParam 传回值则随Hook的种类和nCode的值之不同而不同。

 

因这个参数是一个 Function的Address所以我们固定将Hook Function放在.Bas中,并以AddressOf HookFunc传入。至于Hook Function的名称我们可以任意给定,不一定叫HookFunc

 

hmod 代表.DLL的hInstance,如果是Local Hook,该值可以是Null(VB中可传0进去),而如果是Remote Hook,则可以使用GetModuleHandle(".dll名称")来传入。

 

dwThreadId 代表执行这个Hook的ThreadId,如果不设定是那个Thread来做,则传0(所以 一般来说,Remote Hook传0进去),而VB的Local Hook一般可传App.ThreadId进去

 

值回值 如果SetWindowsHookEx()成功,它会传回一个值,代表目前的Hook的Handle, 这个值要记录下来。

 

因为A程序可以有一个System Hook(Remote Hook),如KeyBoard Hook,而B程序也来设一 个Remote的KeyBoard Hook,那麽到底KeyBoard的信息谁所拦截?答案是,最後的那一个 所拦截,也就是说A先做keyboard Hook,而後B才做,那信息被B拦截,那A呢?就看B的 Hook Function如何做。如果B想让A的Hook Function也得这个信息,那B就得呼叫 CallNextHookEx()将这信息Pass给A,於是产生Hook的一个连线。如果B中不想Pass这信息给A,那就不要呼叫CallNextHookEx()。

 

Declare Function CallNextHookEx Lib "user32" Alias "CallNextHookEx" _

(ByVal hHook As Long, _

ByVal ncode As Long, _

ByVal wParam As Long, _

lParam As Any) As Long

 

hHook值是SetWindowsHookEx()的传回值,nCode, wParam, lParam则是Hook Procedure 中的三个参数。

 

最後是将这Hook去除掉,请呼叫UnHookWindowHookEx()

 

Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx" _

(ByVal hHook As Long) As Long

 

hHook便是SetWindowsHookEx()的传回值。此时,以上例来说,B程序结束Hook,则换A可 以直接拦截信息。

 

 

KeyBoard Hook的范例

 

Hook Function的三个参数

 

 

nCode wParam lParam 传回值

HC_ACTION或HC_NOREMOVE 表按键Virtual Key 与WM_KEYDOWN同 若信息要被处理传0 反之传1

 

 

Public hHook as Long

 

Public Sub UnHookKBD()

 

If hnexthookproc <> 0 Then

 

UnhookWindowsHookEx hHook

hHook = 0

 

End If

 

End Sub

 

 

Public Function EnableKBDHook()

 

If hHook <> 0 Then Exit Function

hhook = SetWindowsHookEx(WH_KEYBOARD, AddressOf MyKBHFunc, App.hInstance, App.ThreadId)

 

End Function

 

Public Function MyKBHFunc(ByVal iCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

 

MyKBHfunc = 0 '表示要处理这个信息

 

If wParam = vbKeySnapshot Then '侦测 有没有按到PrintScreen键

 

MyKBHFunc = 1 '在这个Hook便吃掉这个信息

 

End If

Call CallNextHookEx(hHook, iCode, wParam, lParam) '传给下一个Hook

 

End Function

 

  至於其他的 Hook的详细资料与nCode,wParam, lParam的意义,请查Win32 Help

                  如何获得密码窗口的内容------揭开Hook的面纱

 

                                          Pan Ying(zero world)

 

  现在的不少程序都有取得密码窗口的内容的功能,你有没有想过是如何做到这一切的呢?我有一个同学就问过我这样一个问题,当时我也回答不出来,现在我研究了视窗的Hook函数之后总算有了一定的了解。下面就有我来揭开Hook函数的神秘面纱。

 
  先来介绍Hook的含义:

  Hook是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息。举例来说,当你在一个窗口上点击鼠标以后,首先接收信息的是相应的Hook函数,然后才传到相应的应用程序。

 
  如何定义Hook函数:

SetWindowsHookEx:

  用来装入新的Hook函数,其参数列表为下:

int idHook:装入Hook类型,有WH_MOUSE 等。

HOOKPROC lpfn:要装入的Hook函数地址。

HINSTANCE hMod:函数所在的进程,如果为全局Hook函数该函数必须在Dll中。

DWORD dwThreadId:装入哪个进程,如果为全局,则为0。

  返回相应Hook标识。

HookProc:

  您自定义的Hook函数,应具有的参数如下:

int nCode:传入的信息类型。

WPARAM wParam:短整型参数。

LPARAM lParam:长整型参数。

  要在函数中调用CallNextHookEx把信息传给下一个Hook函数。

CallNextHookEx:

  用于将信息传给下一个Hook函数,需要将得到的Hook标识和相应参数传入。

UnhookWindowsHookEx:

  用于将装入的Hook函数从Hook链表中剔除,应传入得到的Hook标识。

下面我们来看一个例子:

  例子原码的下载:HookTest.zip 本程序在Window98和Delphi5下通过。

 一、调用LoadLibrary和GetProcAddress取得函数地址。

  hinstDLL := LoadLibrary(LPCTSTR( 'hooktest.dll'));

  @hkprcSysMsg:=GetProcAddress(hinstDLL, 'MouseProc');

 

二、用SetWindowsHookEx将得到的函数装入。

  hhk:= SetWindowsHookEx(WH_MOUSE,@hkprcSysMsg,hinstDLL, 0);

 

三、Windows会将函数装入到每一个进程中。

 

四、每当鼠标点击,自定义的Hook函数会将点击的窗口标题传给程序的标题。

if (nCode=HC_ACTION)and(WPARAM=WM_LBUTTONDOWN)

 then

  begin

   MyMouse:=CPointer(lPARAM);

   MyHandle2:=MyMouse^.hwnd;

   GetMem(MyString,GetWindowTextlength(myhandle2)+1);

   GetWindowText(MyHandle2,MyString,GetWindowTextlength(myhandle2)+1);

   TempHandle:=myhandle2;

   while (TempHandle<>0) do

   begin

    myHandle2:=TempHandle;

    TempHandle:=GetParent(TempHandle);

   end;

   if (myhandle2<>0)

   then

    SetWindowText(myhandle2,MyString);

   FreeMem(MyString);

  end

就这样完成了得到密码窗口内容的功能。

 

关于 HOOK
[ 作者: 陆麟   添加时间: 2001-6-2 0:04:44 ]
来源:lu0.126.com

大家讨论HOOK太多了.在网络中,概凡谈论到进程控制,十有八九最后会得到一句话:写HOOK.
嘿嘿,知道HOOK运作机理的有几个呢?下面,本人就MSDN文档中没有写到的一点东西稍微讲几句.

以下讲述乃针对全局HOOK而发.

1.设置HOOK过程时返回的前一HOOK地址必须被保存到一个全局共享的内存地址段中.这个共享段的地址不是什么本进程的全局变量,而是所有进程都可以看见的变量.因为,进程级变量进在本进程内可见.当其他进程加载HOOK DLL时,HOOK DLL里的所有变量都会被RESET.这也就是说:

HHOOK hk;

//set and get HHOOK here

return hk();

这样的描述是不能跳转到前一HOOK的.这一点,甚至在Jeffrey Richter的经典书籍<>里都描述错了.

正确的做法是:

#pragma data_seg("dt")

HHOOK prehook=0;

#pragma data_seg()

然后到VC的LINK OPITION里加上:

-SECTION:dt,RWS

这样,prehook就被搞到系统中被共享了.记住,一定要给prehook初始化.否则,MS编译器的编译器会LINK错误.

 

2.只有使用USER32.DLL的进程才会被INJECT.所以,HOOK并不是万能的.而且,用了USER32.DLL,也不一定会被INJECT.这里有个很好的例子就是整个OS启动中第一个被启动的WIN32进程:KERNEL32.DLL.大家很奇怪,KERNEL32.DLL是个DLL,怎么也会被作为进程加载?但是事实的确是这样的,顺便给大家再上一节98启动课吧.KERNEL32.DLL作为一个独立的进程,启动时加载了MSGSRV32.EXE.而MSGSRV32.EXE又启动了SPOOL32.EXE, SPOOL32.EXE启动了MPREXE.EXE.MPREXE.EXE可不能小看.我敢担保全中国没几个人真正知道它的作用的.MPREXE.EXE不仅是网络客户端部件启动的核心,更是WIN98的SERVICE的SCM.所有的WIN98的SERVICE都是由MPREXE.EXE启动的.WIN98的SERVICE都在HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/RunServices里呆者哩.大家都傻眼了吧.:DDD 有一点很令人奇怪, 那就是如果MPREXE.EXE运作不正常,那么SHELL绝对起不来.SHELL却是有MSGSRV32.EXE启动的.看来MPREXE和MSGSRV32有一套内部沟通机制啊.有了SHELL,就什么都有了.其他的东西被SHELL启动就难说准了.反正80%的程序是由SHELL启动的.好了,WIN98启动暂且讲到这里.我们继续原先的话题.KERNEL32.DLL居然就无法用HOOK入侵.大家如果不信的话,就试试看吧.

3.尽管使用USER32.DLL的进程会被INJECT. 但是这里还有一个技巧,那就是HOOK DLL是在进程第一次发出USER32调用的时候才被加载. 大家又目瞪口呆了吧.:) 这也就是说,在你发出USER32调用之前, HOOK DLL根本拿你没办法. 哇,真够幽默啊.:)))由于在启动HOOK前的进程绝对都是在调用GetMessage(...)/PeekMessage(...)中,那么HOOK DLL一下子满足了加载条件了.

 
4.加载HOOK时,HMODULE一定要正确,否则,系统就无法正确加载HOOK过程.千万不要用0代替HMODULE,因为0代表的是EXE映象的HINSTANCE(其实就是HMODULE).

好了.今天就写到这里.此文该算本主页里又一篇经典了吧.:)
 
 

 


 
 
   
 
 

   
  深入浅出HOOKS(下)

      

利用VB建立鼠标键盘操作回放

    很多的教学软件或系统监视软件可以自动记录回放用户的输入文字或点击按钮等操作操作,这个功能的实现是使用

了Windows的Hook函数。本文介绍如何通过使用VB来实现鼠标键盘操作的纪录和回放。

    Windows提供API函数SetwindowsHookEx来建立一个Hook,通过这个函数可以将一个程序添加到Hook链中监视Windows

消息,函数语法为:

    Public Declare Function SetWindowsHookEx Lib "user32" _

 

用消息拦截技术制作系统日志

 

康帕斯(中国)国际信息服务有限公司 马文骞 

01-6-7 下午 03:33:05

 

--------------------------------------------------------------------------------

 

 

能够完整记录电脑使用情况的日志文件在 Windows系统安全管理方面的作用是不可低估的。本文介绍了利用消息拦截技术制作日志文件的方法,其中的关键函数是一个未公开的 API系统调用。

 

 

一、利用钩子(Hook)拦截系统消息

 

日志文件对于一个大企业内部网络的维护与管理是至关重要的。另外还有许多其它场合也离不开日志的使用,例如:多人共享一台电脑,或在家庭中要记录儿童使用电脑的细节,等等。

 

日志程序若想完整记录电脑运行期间有哪些软件启动过、各使用了多长时间、以及使用浏览器访问互联网的情况等,必须对系统级消息进行拦截。RegisterShellHook是一个未公开的 API系统函数,它可以帮助日志程序在整个 Windows系统范围内感知到其它窗体的创建、激活或关闭等消息,而且不要求这些窗体与日志程序有父子关系,哪怕是 Windows最高级别的窗体也可以。RegisterShellHook 调用方法为:

 

Public Declare Function RegisterShellHook Lib "Shell32" Alias "#181" _

(ByVal hwnd As Long, ByVal nAction As Long) As Long

 

其中参数hwnd为日志程序的句柄,参数 nAction为所要进行操作的代码。具体的调用细节参见下面的例子及其注释。

 

 

二、将日志程序隐藏起来

 

把日志程序的Visible属性设为False当然是必要的一步。然后是 ShowInTaskbar属性也设为 False,以便其在 Windows的任务栏中不出现。最后,为了在 CTRL+ALT+DEL 所弹出的列表中隐藏日志程序,需要调用RegisterServiceProcess函数:

 

Public Declare Function RegisterServiceProcess Lib "kernel32" _

(ByVal dwProcessID As Long, ByVal dwType As Long) As Long

 

其中参数dwType是操作代码,值“1”表示从CTRL+ALT+DEL列表中去除,值“0”表示在列表中恢复;参数 dwProcessID是要在列表中去除或恢复的进程标识,可以用GetCurrentProcessId() API 函数得到日志程序的进程标识,也可以用更简便的方法,即把 dwProcessID参数置为空值,其含义是用当前程序的进程标识作为参数(见下例)。

 

另外,为了让日志程序在 Windows每次启动时都能自动运行,需要修改注册表,即在注册表的下述位置新建一个以日志程序的路径及名称为值的“串值”:

 

/HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Run

 

此外,产生的日志文件也应妥为隐藏,最好用 Winsock控件随时向服务器传送。

为了简洁,下面的例子仅将日志文件放在了根目录,并且略去了用TCP/IP传送文件的代码。

 

 

三、一个完整的例子

 

下面的代码虽然短小,却是一个完整的能自我隐藏的日志程序(用 VB6.0实现,在 Win98下测试通过)。

 

' 窗体部分的代码(Form1.frm)

Option Explicit

Private Sub Form_Load()

Dim tmp As Long

' 将日志程序的名称从 CTRL+ALT+DEL 列表中清除

tmp = RegisterServiceProcess(ByVal 0&, 1)

Timer1.Interval = 60000 ' 定时器的作用是每隔一分钟将日志存盘

' 定义一个新的系统级的消息类型

Msg_ID = RegisterWindowMessage("SHELLHOOK")

Call RegisterShellHook(hwnd, 1) ' 调用未公开的函数(进行注册)

' 实施拦截:在存储了原入口地址的同时,将新地址指向自定义的函数WindowProc

Original = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)

End Sub

Private Sub Form_Unload(Cancel As Integer)

Dim tmp As Long

Call RegisterShellHook(hwnd, 0) ' 调用未公开的函数(取消注册)

tmp = SetWindowLong(hwnd, GWL_WNDPROC, Original) ' 将入口地址还原

End Sub

Private Sub Timer1_Timer()

If Len(Text1.Text) > 0 Then

Open "C:/SystemLog.Sys" For Append As #1 ' 以“添加”方式打开日志

Print #1, Text1.Text ' 日志自动存盘

Text1.Text = ""

Close #1

End If

End Sub

' 模块部分的代码(模块1.bas)

Public Declare Function RegisterShellHook Lib "Shell32" Alias "#181" _

(ByVal hwnd As Long, ByVal nAction As Long) As Long

Public Declare Function RegisterWindowMessage Lib "user32" Alias _

"RegisterWindowMessageA" (ByVal lpString As String) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _

(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _

(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _

(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal _

wParam As Long, ByVal lParam As Long) As Long

Public Declare Function RegisterServiceProcess Lib "kernel32" _

(ByVal dwProcessID As Long, ByVal dwType As Long) As Long

Const HSHELL_WINDOWCREATED = 1 ' 系统级的窗体被创建

Const HSHELL_WINDOWDESTROYED = 2 ' 系统级的窗体即将被关闭

'Const HSHELL_ACTIVATESHELLWINDOW = 3 ' SHELL 的主窗体将被激活(本例未用)

Const HSHELL_WINDOWACTIVATED = 4 ' 系统级的窗体被激活

'Const HSHELL_GETMINRECT = 5 ' 窗体被最大化或最小化(本例未用)

'Const HSHELL_REDRAW = 6 ' Windows 任务栏被刷新(本例未用)

'Const HSHELL_TASKMAN = 7 ' 任务列表的内容被选中(本例未用)

'Const HSHELL_LANGUAGE = 8 ' 中英文切换或输入法切换(本例未用)

Public Const GWL_WNDPROC = -4 ' 该索引用来创建窗口类的子类

Public Msg_ID As Long, Original As Long

Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal _

wParam As Long, ByVal lParam As Long) As Long ' 回调函数

Dim tmp1 As String, tmp2 As String, i As Long

If uMsg = Msg_ID Then

tmp1 = String(200, "*")

i = GetWindowText(lParam, tmp1, 200) ' 取窗体的标题

If i > 0 Then tmp1 = Left(tmp1, i) Else tmp1 = "未命名"

tmp1 = tmp1 + " " + Str(Date) + " " + Str(Time) + vbCrLf ' 加入日期

' 下面对窗体句柄值进行格式化的目的是为了日志文件在视觉上更美观

tmp2 = Format(lParam, "000000")

If Right(Form1.Text1, 2) <> vbCrLf Then tmp2 = vbCrLf + tmp2

Select Case wParam

Case HSHELL_WINDOWCREATED

Form1.Text1 = Form1.Text1 + tmp2 + " 创建:" + tmp1

Case HSHELL_WINDOWDESTROYED

Form1.Text1 = Form1.Text1 + tmp2 + " 关闭:" + tmp1

Case HSHELL_WINDOWACTIVATED

Form1.Text1 = Form1.Text1 + tmp2 + " 激活:" + tmp1

' 为了程序简洁,本例仅处理“创建”、“激活”和“关闭”这三个消息,

' 其实就生成日志文件的目的,上述三个消息已基本够用。

' Case ...

' ...

End Select

Else

' 使用已被存储下来的原入口地址

WindowProc = CallWindowProc(Original, hwnd, uMsg, wParam, lParam)

End If

End Function

 

下面列出的即为上述日志程序所产生的日志文件(长约十分钟的片段)。从中可以看出在该时间段内的电脑使用情况:曾拨号上网、浏览过“计算机世界”、收过邮件、访问过注册表等。左列的数字是相应窗体的句柄。

 

002624 激活:Project1 - Microsoft Visual Basic [设计]

002624 关闭:Microsoft Visual Basic [设计]

001692 创建:正在连接到 95963

001692 激活:正在连接到 95963

003512 关闭:Hotmail - 通行全球的免费 Web 电子邮件 - Microsoft Internet Explorer

001880 创建:未命名 01-6-6 16:01:25

001880 激活:未命名 01-6-6 16:01:25

001880 激活:计算机世界网-应用与方案-首页 - Microsoft Internet Explorer

001880 激活:计算机世界网-应用与方案-应用编程 - Microsoft Internet Explorer

003488 创建:Microsoft Internet Explorer 01-6-6 16:07:40

003488 激活:Microsoft Internet Explorer 01-6-6 16:07:41

003488 关闭:计算机世界网-用屏幕取词技术实现动态标注 - Microsoft Internet Explorer

001880 激活:计算机世界网-e海航标-首页 - Microsoft Internet Explorer

001880 关闭:计算机世界网-e海航标-首页 - Microsoft Internet Explorer

001132 激活:浏览 - C:/

001132 关闭:浏览 - C:/

002772 创建:Outlook Express 01-6-6 16:10:41

002772 激活:Outlook Express 01-6-6 16:10:41

002772 激活:收件箱 - Outlook Express

002772 关闭:收件箱 - Outlook Express

003920 关闭:浏览 - 我的电脑

000640 创建:注册表编辑器

000640 激活:注册表编辑器

000640 关闭:注册表编辑器

003756 创建:未命名 01-6-6 16:11:30

003756 关闭:未命名 01-6-6 16:11:30

001328 创建:网络监视器

001328 激活:网络监视器

001328 激活:网络监视器 - 0 连接到 //CD_PROGRAM

001328 关闭:网络监视器 - 0 连接到 //CD_PROGRAM

002700 关闭:连接到 95963

001804 关闭:未命名 01-6-6 16:13:13

 

Platform SDK: Interprocess Communications

Monitoring System Events

The following example uses a variety of thread-specific hook procedures to monitor the system for events affecting a thread. It demonstrates how to process events for the following types of hook procedures:

 

WH_CALLWNDPROC

WH_CBT

WH_DEBUG

WH_GETMESSAGE

WH_KEYBOARD

WH_MOUSE

WH_MSGFILTER

 

The user can install and remove a hook procedure by using the menu. When a hook procedure is installed and an event that is monitored by the procedure occurs, the procedure writes information about the event to the client area of the application's main window.

 

#define NUMHOOKS 7

 

// Global variables

 

typedef struct _MYHOOKDATA

{

    int nType;

    HOOKPROC hkprc;

    HHOOK hhook;

} MYHOOKDATA;

 

MYHOOKDATA myhookdata[NUMHOOKS];

 

LRESULT WINAPI MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam,

    LPARAM lParam)

{

    static BOOL afHooks[NUMHOOKS];

    int index;

    static HMENU hmenu;

 

    switch (uMsg)

    {

        case WM_CREATE:

 

            // S***e the menu handle.

 

            hmenu = GetMenu(hwndMain);

 

            // Initialize structures with hook data. The menu-item

            // identifiers are defined as 0 through 6 in the

            // header file. They can be used to identify array

            // elements both here and during the WM_COMMAND

            // message.

 

            myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;

            myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;

            myhookdata[IDM_CBT].nType = WH_CBT;

            myhookdata[IDM_CBT].hkprc = CBTProc;

            myhookdata[IDM_DEBUG].nType = WH_DEBUG;

            myhookdata[IDM_DEBUG].hkprc = DebugProc;

            myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;

            myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;

            myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;

            myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;

            myhookdata[IDM_MOUSE].nType = WH_MOUSE;

            myhookdata[IDM_MOUSE].hkprc = MouseProc;

            myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;

            myhookdata[IDM_MSGFILTER].hkprc = MessageProc;

 

            // Initialize all flags in the array to FALSE.

 

            memset(afHooks, FALSE, sizeof(afHooks));

 

            return 0;

 

        case WM_COMMAND:

            switch (LOWORD(wParam))

            {

                 // The user selected a hook command from the menu.

 

                case IDM_CALLWNDPROC:

                case IDM_CBT:

                case IDM_DEBUG:

                case IDM_GETMESSAGE:

                case IDM_KEYBOARD:

                case IDM_MOUSE:

                case IDM_MSGFILTER:

 

                    // Use the menu-item identifier as an index

                    // into the array of structures with hook data.

 

                    index = LOWORD(wParam);

 

                    // If the selected type of hook procedure isn't

                    // installed yet, install it and check the

                    // associated menu item.

 

                    if (!afHooks[index])

                    {

                        myhookdata[index].hhook = SetWindowsHookEx(

                            myhookdata[index].nType,

                            myhookdata[index].hkprc,

                            (HINSTANCE) NULL, GetCurrentThreadId());

                        CheckMenuItem(hmenu, index,

                            MF_BYCOMMAND | MF_CHECKED);

                        afHooks[index] = TRUE;

                    }

 

                    // If the selected type of hook procedure is

                    // already installed, remove it and remove the

                    // check mark from the associated menu item.

 

                    else

                    {

                        UnhookWindowsHookEx(myhookdata[index].hhook);

                        CheckMenuItem(hmenu, index,

                            MF_BYCOMMAND | MF_UNCHECKED);

                        afHooks[index] = FALSE;

                    }

 

                default:

                    return (DefWindowProc(hwndMain, uMsg, wParam,

                        lParam));

            }

            break;

 

            //

            // Process other messages.

            //

 

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}

 

/****************************************************************

  WH_CALLWNDPROC hook procedure

 ****************************************************************/

 

LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szCWPBuf[256];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process message

        return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,

                wParam, lParam);

 

    // Call an application-defined function that converts a message

    // constant to a string and copies it to a buffer.

 

    LookUpTheMessage((PMSG) lParam, szMsg);

 

    hdc = GetDC(hwndMain);

 

    switch (nCode)

    {

        case HC_ACTION:

            cch = wsprintf(szCWPBuf,

               "CALLWNDPROC - tsk: %ld, msg: %s, %d times   ",

                wParam, szMsg, c++);

            TextOut(hdc, 2, 15, szCWPBuf, cch);

            break;

 

        default:

            break;

    }

 

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,

        wParam, lParam);

}

 

/****************************************************************

  WH_GETMESSAGE hook procedure

 ****************************************************************/

 

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szMSGBuf[256];

    CHAR szRem[16];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0) // do not process message

        return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,

            wParam, lParam);

 

    switch (nCode)

    {

        case HC_ACTION:

            switch (wParam)

            {

                case PM_REMOVE:

                    lstrcpy(szRem, "PM_REMOVE");

                    break;

 

                case PM_NOREMOVE:

                    lstrcpy(szRem, "PM_NOREMOVE");

                    break;

 

                default:

                    lstrcpy(szRem, "Unknown");

                    break;

            }

 

            // Call an application-defined function that converts a

            // message constant to a string and copies it to a

            // buffer.

 

            LookUpTheMessage((PMSG) lParam, szMsg);

 

            hdc = GetDC(hwndMain);

            cch = wsprintf(szMSGBuf,

                "GETMESSAGE - wParam: %s, msg: %s, %d times   ",

                szRem, szMsg, c++);

            TextOut(hdc, 2, 35, szMSGBuf, cch);

            break;

 

        default:

            break;

    }

 

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,

        wParam, lParam);

}

 

/****************************************************************

  WH_DEBUG hook procedure

 ****************************************************************/

 

LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szBuf[128];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process message

        return CallNextHookEx(myhookdata[DEBUG].hhook, nCode,

            wParam, lParam);

 

    hdc = GetDC(hwndMain);

 

    switch (nCode)

    {

        case HC_ACTION:

            cch = wsprintf(szBuf,

                "DEBUG - nCode: %d, tsk: %ld, %d times   ",

                nCode,wParam, c++);

            TextOut(hdc, 2, 55, szBuf, cch);

            break;

 

        default:

            break;

    }

 

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[DEBUG].hhook, nCode, wParam,

        lParam);

}

 

/****************************************************************

  WH_CBT hook procedure

 ****************************************************************/

 

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szBuf[128];

    CHAR szCode[128];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process message

        return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,

            lParam);

 

    hdc = GetDC(hwndMain);

 

    switch (nCode)

    {

        case HCBT_ACTIVATE:

            lstrcpy(szCode, "HCBT_ACTIVATE");

            break;

 

        case HCBT_CLICKSKIPPED:

            lstrcpy(szCode, "HCBT_CLICKSKIPPED");

            break;

 

        case HCBT_CREATEWND:

            lstrcpy(szCode, "HCBT_CREATEWND");

            break;

 

        case HCBT_DESTROYWND:

            lstrcpy(szCode, "HCBT_DESTROYWND");

            break;

 

        case HCBT_KEYSKIPPED:

            lstrcpy(szCode, "HCBT_KEYSKIPPED");

            break;

 

        case HCBT_MINMAX:

            lstrcpy(szCode, "HCBT_MINMAX");

            break;

 

        case HCBT_MOVESIZE:

            lstrcpy(szCode, "HCBT_MOVESIZE");

            break;

 

        case HCBT_QS:

            lstrcpy(szCode, "HCBT_QS");

            break;

 

        case HCBT_SETFOCUS:

            lstrcpy(szCode, "HCBT_SETFOCUS");

            break;

 

        case HCBT_SYSCOMMAND:

            lstrcpy(szCode, "HCBT_SYSCOMMAND");

            break;

 

        default:

            lstrcpy(szCode, "Unknown");

            break;

    }

 

    cch = wsprintf(szBuf, "CBT - nCode: %s, tsk: %ld, %d times   ",

        szCode, wParam, c++);

    TextOut(hdc, 2, 75, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,

        lParam);

}

 

/****************************************************************

  WH_MOUSE hook procedure

 ****************************************************************/

 

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szBuf[128];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process the message

        return CallNextHookEx(myhookdata[MOUSE].hhook, nCode,

            wParam, lParam);

 

    // Call an application-defined function that converts a message

    // constant to a string and copies it to a buffer.

 

    LookUpTheMessage((PMSG) lParam, szMsg);

 

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf,

        "MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times   ",

        nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);

    TextOut(hdc, 2, 95, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[MOUSE].hhook, nCode, wParam,

        lParam);

}

 

/****************************************************************

  WH_KEYBOARD hook procedure

 ****************************************************************/

 

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szBuf[128];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process message

        return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode,

            wParam, lParam);

 

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf, "KEYBOARD - nCode: %d, vk: %d, %d times ",

        nCode, wParam, c++);

    TextOut(hdc, 2, 115, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode, wParam,

        lParam);

}

 

/****************************************************************

  WH_MSGFILTER hook procedure

 ****************************************************************/

 

LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    CHAR szBuf[128];

    CHAR szMsg[16];

    CHAR szCode[32];

    HDC hdc;

    static int c = 0;

    int cch;

 

    if (nCode < 0)  // do not process message

        return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,

            wParam, lParam);

 

    switch (nCode)

    {

        case MSGF_DIALOGBOX:

            lstrcpy(szCode, "MSGF_DIALOGBOX");

            break;

 

        case MSGF_MENU:

            lstrcpy(szCode, "MSGF_MENU");

            break;

 

        case MSGF_SCROLLBAR:

            lstrcpy(szCode, "MSGF_SCROLLBAR");

            break;

 

        default:

            wsprintf(szCode, "Unknown: %d", nCode);

            break;

    }

 

    // Call an application-defined function that converts a message

    // constant to a string and copies it to a buffer.

 

    LookUpTheMessage((PMSG) lParam, szMsg);

 

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf,

        "MSGFILTER  nCode: %s, msg: %s, %d times    ",

        szCode, szMsg, c++);

    TextOut(hdc, 2, 135, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,

        wParam, lParam);

}

Built on Thursday, October 12, 2000

        Alias "SetWindowsHookExA" _

        (ByVal idHook As Long, _

        ByVal lpfn As Long, _

        ByVal hmod As Long, _

        ByVal dwThreadId As Long) As Long

    其中参数idHook指定建立的监视函数类型。通过Windows MSDN帮助可以看到,SetwindowsHookEx函数提供15种不同

的消息监视类型,在这里我们将使用WH_JOURNALRECORD和WH_JOURNALPLAYBACK来监视键盘和鼠标操作。参数lpfn指定消

息函数,在相应的消息产生后,系统会调用该函数并将消息值传递给该函数供处理。函数的一般形式为:

    Hookproc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;

    其中code为系统指示标记,wParam和lParam为附加参数,根据不同的消息监视类型而不同。只要在程序中建立这样

一个函数再通过SetwindowsHookEx函数将它加入到消息监视链中就可以处理消息了。

    在不需要监视系统消息时需要调用提供UnHookWindowsHookEx来解除对消息的监视。

    WH_JOURNALRECORD和WH_JOURNALPLAYBACK类型是两种相反的Hook类型,前者获得鼠标、键盘动作消息,后者回放鼠

标键盘消息。所以在程序中我们需要建立两个消息函数,一个用于纪录鼠标键盘操作并保存到一个数组中,另一个用于

将保存的操作返给系统回放。

    下面是具体的程序实现:首先建立一个新工程,在Form1中加入三个CommandButton控件用于控制消息钩子,另外还

可以增加若干Command或者TextBox控件用于检验操作回放的效果。然后在工程中增加一个模块文件,在模块中加入以下

定义和代码:

 

Option Explicit

 

Public Type EVENTMSG

        message As Long

        paramL As Long

        paramH As Long

        time As Long

        hwnd As Long

End Type

 

Public Declare Function CallNextHookEx Lib "user32" _

        (ByVal hHook As Long, _

        ByVal ncode As Long, _

        ByVal wParam As Long, _

        ByVal lParam As Long) As Long

Public Declare Function SetWindowsHookEx Lib "user32" _

        Alias "SetWindowsHookExA" _

        (ByVal idHook As Long, _

        ByVal lpfn As Long, _

        ByVal hmod As Long, _

        ByVal dwThreadId As Long) As Long

Public Declare Sub CopyMemoryT2H Lib "kernel32" _

        Alias "RtlMoveMemory" _

        (ByVal Dest As Long, _

        Source As EVENTMSG, _

        ByVal Length As Long)

Public Declare Sub CopyMemoryH2T Lib "kernel32" _

        Alias "RtlMoveMemory" _

        (Dest As EVENTMSG, _

        ByVal Source As Long, _

        ByVal Length As Long)

Public Declare Function UnhookWindowsHookEx Lib "user32" _

        (ByVal hHook As Long) As Long

 

Public Const WH_JOURNALPLAYBACK = 1

Public Const WH_JOURNALRECORD = 0

Public Const HC_SYSMODALOFF = 5

Public Const HC_SYSMODALON = 4

Public Const HC_SKIP = 2

Public Const HC_GETNEXT = 1

Public Const HC_ACTION = 0

 

Public EventArr(1000) As EVENTMSG

Public EventLog As Long

Public PlayLog As Long

Public hHook As Long

Public hPlay As Long

Public recOK As Long

Public canPlay As Long

Public bDelay As Boolean

 

Public Function HookProc(ByVal iCode As Long, ByVal wParam As Long, _

        ByVal lParam As Long) As Long

    Dim Result As Long

   

    recOK = 1

    Result = 0

 

    If iCode < 0 Then   'iCode小于0必须直接调用下一个消息钩子函数

        Result = CallNextHookEx(hHook, iCode, wParam, lParam)

    ElseIf iCode = HC_SYSMODALON Then   '不允许纪录

        recOK = 0

    ElseIf iCode = HC_SYSMODALOFF Then  '允许纪录

        recOK = 1

    ElseIf ((recOK > 0) And (iCode = HC_ACTION)) Then

        '将消息纪录在纪录队列中

        CopyMemoryH2T EventArr(EventLog), lParam, Len(EventArr(EventLog))

        EventLog = EventLog + 1

        If EventLog >= 1000 Then

            '当纪录大于1000后释放消息钩子

            UnhookWindowsHookEx hHook

        End If

    End If

    HookProc = Result

End Function

 

Public Function PlaybackProc(ByVal iCode As Long, ByVal wParam As Long, _

        ByVal lParam As Long) As Long

    Dim Result As Long

   

    canPlay = 1

    Result = 0

 

    If iCode < 0 Then   'iCode小于0必须直接调用下一个消息钩子函数

        Result = CallNextHookEx(hPlay, iCode, wParam, lParam)

    ElseIf iCode = HC_SYSMODALON Then   '不允许回放

        canPlay = 0

    ElseIf iCode = HC_SYSMODALOFF Then  '允许回放

        canPlay = 1

    ElseIf ((canPlay = 1) And (iCode = HC_GETNEXT)) Then

        If bDelay Then

            bDelay = False

            Result = 50

        End If

        '从纪录队列中取出消息并赋予lParam指针指向的EVENTMSG区域

        CopyMemoryT2H lParam, EventArr(PlayLog), Len(EventArr(EventLog))

    ElseIf ((canPlay = 1) And (iCode = HC_SKIP)) Then

        bDelay = True

        PlayLog = PlayLog + 1

    End If

   

    If PlayLog >= EventLog Then

        UnhookWindowsHookEx hPlay

    End If

    PlaybackProc = Result

End Function

 

    在Form1的代码窗口中加入以下代码:

Option Explicit

 

Private Sub Command1_Click()

    EventLog = 0

    hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, _

            App.hInstance, 0)

    Command2.Enabled = True

    Command1.Enabled = False

End Sub

 

Private Sub Command2_Click()

    UnhookWindowsHookEx hHook

    hHook = 0

 

    Command1.Enabled = True

    Command2.Enabled = False

    Command3.Enabled = True

End Sub

 

Private Sub Command3_Click()

    PlayLog = 0

    hPlay = SetWindowsHookEx(WH_JOURNALPLAYBACK, AddressOf PlaybackProc, _

            App.hInstance, 0)

    Command3.Enabled = False

End Sub

 

Private Sub Form_Load()

    Command1.Caption = "纪录"

    Command2.Caption = "停止"

    Command3.Caption = "回放"

    Command2.Enabled = False

    Command3.Enabled = False

End Sub

 

    运行程序,点击“纪录”按钮,然后在TextBox中输入一些文字或者在窗口上移动光标后再按“停止”键停止消息

纪录,然后按“回放”按钮,可以看到刚才鼠标键盘的操作被丝毫不差的回放了出来。

    从上面的程序可以看到:通过WH_JOURNALRECORD可以建立一个鼠标键盘消息钩子,当每一个鼠标键盘消息产生时被

钩子函数被调用。在钩子函数中可以将消息保存在消息事件队列中。然后通过WH_JOURNALPLAYBACK建立消息回放钩子,

当每一次系统可以回放消息时就会调用钩子函数,在钩子函数中就可以从消息队列中取出原来纪录的消息返回给系统。

这样就实现了鼠标键盘操作的纪录和回放。
 
 
 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值