钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之前处理它们。钩子的种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息,鼠标钩子可以截获鼠标消息,外壳钩子可以截获启动和关闭应用程序的消息,日志钩子可以监视和记录输入事件。钩子分为线程专用钩子和全局钩子,线程专用钩子只监视指定的线程,要监视系统中的所有线程,必须用到全局钩子。对于全局钩子,钩子函数必须包含在独立的动态链接库(DLL)中,这样才能被各种相关联的应用程序调用。在WINDOWS中,日志钩子是个很特别的钩子,它只有全局钩子一种,是键盘鼠标等输入设备的消息在系统消息队列被取出时发生的,而且系统中只能存在一个这样的日志钩子,更重要是,它不必用在动态链接库中,这样可以省却了为安装一个全局钩子而建立一个动态链接库的麻烦。利用日志钩子,我们可以监视各种输入事件,下面的示例可以用来记录键盘的输入,当有按键发生时,自动记录按键动作的日期和时间以及当前激活的窗口名称。本示例在中文WIN98,Borland C++ Builder4中编译通过。
---- 1.新建一个工程,在窗体Form1中放置两个按钮Button1和Button2, CAPTION分别 为“安装日志钩子”和“卸载日志钩子”。
---- 2. 定义如下全局变量:
HHOOK g_hLogHook=NULL; //钩子变量 HWND g_hLastFocus=NULL; //记录上一次得到焦点的窗口句柄 const int KeyPressMask=0x80000000; //键盘掩码常量 char g_PrvChar; //保存上一次按键值 3.在Button1的OnClick事件中输入: void __fastcall TForm1::Button1Click(TObject *Sender) { if (g_hLogHook==NULL) g_hLogHook = SetWindowsHookEx (WH_JOURNALRECORD, (HOOKPROC)JournalLogProc, HInstance,0); //安装日志钩子 } 4.在Button2的OnClick事件中输入: void __fastcall TForm1::Button2Click(TObject *Sender) { if (g_hLogHook!=NULL) {UnhookWindowsHookEx(g_hLogHook); g_hLogHook=NULL; } //卸载日志钩子 } 5.输入钩子回调函数: HOOKPROC JournalLogProc(int iCode, WPARAM wParam, LPARAM lParam) { if (iCode<0) return (HOOKPROC)CallNextHookEx (g_hLogHook,iCode,wParam,lParam); if (iCode="=HC_ACTION)" {EVENTMSG *pEvt="(EVENTMSG" *)lParam; int i; HWND hFocus; //保存当前活动窗口句柄 char szTitle[256]; //当前窗口名称 char szTime[128]; //保存当前的日期和时间 FILE *stream="fopen(“c:\\logfile.txt”,"a+t");" if (pEvt->message==WM_KEYDOWN) {int vKey=LOBYTE(pEvt- >paramL); // 取得虚拟键值 char ch; char str[10]; hFocus=GetActiveWindow(); //取得当前活动窗口句柄 if(g_hLastFocus!=hFocus) //当前活动窗口是否改变 {GetWindowText(hFocus,szTitle,256); g_hLastFocus=hFocus; strcpy(szTime,DateTimeToStr(Now()) .c_str()); //得到当前的日期时间 fprintf(stream,"%c%s%c%c%s", 10,szTime,32,32,szTitle); //写入文件 fprintf(stream,"%c%c",32,32); } int iShift=GetKeyState(0x10); //测试SHIFT,CAPTION,NUMLOCK等键是否按下 int iCapital=GetKeyState(0x14); int iNumLock=GetKeyState(0x90); bool bShift=(iShift & KeyPres
|