Delphi 屏幕取詞

要建個DLL實現鉤子 unit GetWord;

interface

uses SysUtils, windows, messages;

const NHD_GETWORD_TIMER = 2; const NHD_MAX_TEXTLEN = 1024; const NHD_WIN_INITPOSX = -1; const NHD_WIN_INITPOSY = -1; const NHD_FLYWIN_WIDTH = 1; const NHD_FLYWIN_HEIGHT = 1; const NHD_CLASSNAME_LEN = 256; const NHD_GW_WAITING_TIME = 200; //get word waiting time;

(設置屏幕抓取函數) type TBL_SetFlag32 = function (nFlag : word; //設置是否取詞 hNotifyWnd : HWND; //當取詞後得窗口句柄 MouseX : integer; //X座標 MouseY : integer): DWORD;stdcall; //Y座標 (* 功能: 啓動或停止取詞。 參數: nFlag [輸入] 指定下列值之一: GETWORD_ENABLE: 開始取詞。在重畫被取單詞區域前設置此標誌。nhw32.dll是通過 重畫單詞區域,截取TextOutA, TextOutW, ExtTextOutA, ExtTextOutW等Windows API函數的參數來取詞的。 GETWORD_DISABLE: 停止取詞。 hNotifyWnd [輸入] 通知窗口句柄。當取到此時,向該通知窗口發送一登記消息:GWMSG_GETWORDOK。 MouseX [輸入] 指定取詞點的X座標。 MouseY [輸入] 指定取詞點的Y座標。 返回值: 可忽略。 *) type TLPRECT = ^TRECT; (定義指針先) type TBL_GetText32 = function(lpszCurWord : pchar; nBufferSize : integer; lpWordRect : TLPRECT ): DWORD;stdcall; (功能: 從內部緩衝區取出單詞文本串。對英語文本,該函數最長取出一行內以空格爲界的三個英文單詞串, 遇空格,非英文字母及除'-'外的標點符號,則終止取詞。對漢字文本,該函數最長取出一行漢字串, 遇英語字母,標點符號等非漢語字符,則終止取詞。該函數不能同時取出英語和漢語字符。 參數: lpszCurWord [輸入] 目的緩衝區指針。 nBufferSize [輸入] 目的緩衝區大小。 lpWordRect [輸出] 指向 RECT 結構的指針。該結構定義了被取單詞所在矩形區域。 返回值: 當前光標在全部詞中的位置。)

type TSetNHW32 = function(): boolean; stdcall; (* 功能: Win NT/2000 環境下的初始化函數。一般在程序開始時,調用一次。 參數: 無。 返回值: 如果成功 TRUE ,失敗 FALSE 。 *)

type TResetNHW32= function():boolean; stdcall; (* 功能: Win NT/2000 環境下的去初始化函數。一般在程序結束時調用。 參數: 無。 返回值: 如果成功 TRUE ,失敗 FALSE 。*)

function NHD_FlyWndProc(hWnd, Msg,wParam,lParam: Integer): Integer; stdcall; function NHD_CreateWindow(hInst: Integer): HWND; procedure NHD_BeginGetWord(ptMousePos: TPOINT);

function NHD_ExitGetWords(): boolean; function NHD_DestroyWindow(): boolean; procedure NHD_FreeLoadedLib(); function NHD_InitGetWords(hInst: THANDLE; hwnd: HWND): HWND; function NHD_LoadGetWordLib(): boolean;

var WinClass: TWndClassA; Inst: Integer; Msg: TMsg;

g_TextBuffer : array[0..1024] of char;

g_hFlyWin : HWND; g_nGWTimerID : word;

g_hGetWordInst : Integer; BL_SetFlag32 : TBL_SetFlag32; BL_GetText32 : TBL_GetText32; SetNHW32 : TSetNHW32; ResetNHW32 : TResetNHW32; g_hNHMainWin : HWND;

g_WM_GetWordOk:WORD; g_bInGetWord : boolean; currpoint:Tpoint; G_Rect : TRECT; implementation

uses unit1;

function NHD_CreateWindow(hInst: Integer): HWND; var hwnd : LongWord; wc : TWndClassA; begin if hInst = 0 then begin result :=0; exit; end;

with wc do begin style := WS_EX_TOPMOST; lpfnWndProc := @NHD_FlyWndProc; (消息處理函數) hInstance := hInst; hbrBackground := color_btnface + 1; lpszClassname := 'NHD_FLYWIN_DEMO'; hicon := 0; hCursor := 0; cbClsExtra := 0; cbWndExtra := 0; end; RegisterClass(wc);

hwnd := CreateWindowEx (WS_EX_TOPMOST or WS_EX_TOOLWINDOW, 'NHD_FLYWIN_DEMO', 'NHD_FlyWindow_Demo', WS_POPUP or WS_VISIBLE, NHD_WIN_INITPOSX, NHD_WIN_INITPOSY, NHD_FLYWIN_WIDTH, NHD_FLYWIN_HEIGHT, 0,
0, hInst, nil);

result := hwnd; end;

function NHD_FlyWndProc(hWnd, Msg,wParam,lParam: Integer): Integer; stdcall; begin //Unhook textout when reveived msg from getword; if msg = g_WM_GetWordOk then begin if g_bInGetWord then begin g_bInGetWord := FALSE; KillTimer(g_hFlyWin, NHD_GETWORD_TIMER); g_nGWTimerID := 0; BL_SetFlag32(GETWORD_DISABLE, 0, 0, 0);

  if wParam = 0 then begin
    BL_GetText32(@g_TextBuffer, sizeof(g_TextBuffer), @G_Rect);
  end;

  PostMessage(g_hNHMainWin, NHD_WM_GETWORD_OK, 0, 0);
  result := 0;
  exit;
end;

end;

result := DefWindowProc(hWnd, msg, wParam, lParam); end;

procedure NHD_GetWordTimerProc(hwnd: HWND; msg: word; idTimer: word; dwTime: DWORD);stdcall; begin //may be proior finished by Getword message; if g_bInGetWord then begin g_bInGetWord := FALSE; //UnHook TextOut; BL_SetFlag32(GETWORD_DISABLE, 0, 0, 0); BL_GetText32(g_TextBuffer, NHD_MAX_TEXTLEN, @G_Rect); end;

KillTimer(g_hFlyWin, NHD_GETWORD_TIMER); g_nGWTimerID := 0;

PostMessage(g_hNHMainWin, NHD_WM_GETWORD_OK, 0, 0); end;

procedure NHD_BeginGetWord(ptMousePos: TPOINT); var szAppClassName : array [0..NHD_CLASSNAME_LEN] of char; hAppWin : LongWord; nFlyWinLeft : integer; nFlyWinWidth : integer; rcAppWin : TRECT ; cmpstr : string; begin

//get window from mouse point; hAppWin := WindowFromPoint(ptMousePos);

//check if the app window is EDIT, if it is, redraw whole line; GetClassName(hAppWin, szAppClassName, NHD_CLASSNAME_LEN);

(DbgPrintf("hAppWin: %x/n", hAppWin); DbgPrintf("ClassName: %s/n", szAppClassName);) cmpstr := trim(strpas(szAppClassName)); Frm_main.Edit2.text := cmpstr;

if ((cmpstr = 'Edit') or //NotePad (cmpstr = 'Internet Explorer_Server') or //IE4.0 (cmpstr = 'RichEdit') or // (cmpstr = 'RichEdit20A') or //WordPad (cmpstr = 'RichEdit20W') or //WordPad (cmpstr = 'HTML_Internet Explorer') or //IE3.0 (cmpstr = 'ThunderTextBox') or //VB Edit (cmpstr = 'ThunderRT5TextBox') or //VB Edit (cmpstr = 'ThunderRT6TextBox') or //VB Edit (cmpstr = 'EXCEL<') or //Excel 2000 (cmpstr = 'EXCEL7') or //Excel 2000 (cmpstr = 'EXCEL6') or //Excel 2000 (cmpstr = 'ConsoleWindowClass') or //NT V86 (cmpstr = 'Edit') or (cmpstr = 'tty') or (cmpstr = 'ttyGrab')) //Word97 then begin GetWindowRect(hAppWin, rcAppWin); nFlyWinLeft := rcAppWin.left - 4; nFlyWinWidth := rcAppWin.right - rcAppWin.left - 8;

//don't not repaint whole line if too long; if (ptMousePos.x - nFlyWinLeft) > 200 then begin nFlyWinLeft := ptMousePos.x - 200; end;

//DbgPrintf("!!!!tty window"); end else begin nFlyWinLeft := ptMousePos.x; nFlyWinWidth := NHD_FLYWIN_WIDTH; end;

//note: move the flywin to cursor pos "x - 1" to aviod mouse shape changing between ARROW and EDIT in edit area; //use SetWindowPos instead of MoveWindow, for MoveWindow can not make menu item redraw. SetWindowPos(g_hFlyWin, HWND_TOPMOST, nFlyWinLeft, ptMousePos.y - 1 , nFlyWinWidth, NHD_FLYWIN_HEIGHT, SWP_NOACTIVATE or SWP_NOREDRAW);

//set flag to avoid re-entry; g_bInGetWord := TRUE;

//hook TextOut; BL_SetFlag32(GETWORD_ENABLE, g_hFlyWin, ptMousePos.x, ptMousePos.y);

MoveWindow(g_hFlyWin, -1, -1, NHD_FLYWIN_WIDTH, NHD_FLYWIN_HEIGHT, TRUE);

g_nGWTimerID := SetTimer(g_hFlyWin, NHD_GETWORD_TIMER, NHD_GW_WAITING_TIME, @NHD_GetWordTimerProc); end;

function NHD_CopyWordsTo(szBuffer: pchar; nBufferSize: Integer):Boolean; var nLen : integer; begin nLen := sizeof(g_TextBuffer); if(nLen + 1) > nBufferSize then begin result := false; exit; end;

ZeroMemory(szBuffer,nBufferSize); CopyMemory(szBuffer, @g_TextBuffer, nLen);

result := true; end;

function NHD_ExitGetWords(): boolean; begin //free libarys: NHD_FreeLoadedLib();

NHD_DestroyWindow();

result := TRUE; end;

function NHD_DestroyWindow(): boolean; begin if g_hFlyWin<>0 then begin DestroyWindow(g_hFlyWin); g_hFlyWin := 0; end;

result := TRUE; end;

procedure NHD_FreeLoadedLib(); begin if g_hGetWordInst<>0 then begin //only valid in windows NT enviroment

if @ResetNHW32<>nil then begin
        ResetNHW32();
end;

FreeLibrary(g_hGetWordInst);
//g_hGetWordInst = 0;

end; end;

function NHD_InitGetWords(hInst: THANDLE; hwnd: HWND): HWND; begin //save NH main window to send run time error messages: g_hNHMainWin := hwnd;

if NHD_LoadGetWordLib=false then begin NHD_FreeLoadedLib(); result := 0; exit; end;

//Create fly_window (cause paint) and show text window; g_hFlyWin := NHD_CreateWindow(hInst); if g_hFlyWin=0 then begin NHD_FreeLoadedLib(); result := 0; exit; end;

g_WM_GetWordOk := RegisterWindowMessage('BL_HASSTRING'); if g_WM_GetWordOk=0 then begin NHD_FreeLoadedLib(); result := 0; exit; end;

result := g_hFlyWin; end;

function NHD_LoadGetWordLib(): boolean; begin g_hGetWordInst := LoadLibrary('nhw32.dll'); if g_hGetWordInst=0 then begin messagebox(0,'裝載動態鏈接庫失敗','警告',mb_ok or mb_iconwarning or mb_applmodal); result := FALSE; exit; end;

@BL_SetFlag32 := GetProcAddress(g_hGetWordInst,'BL_SetFlag32'); if @BL_SetFlag32=nil then begin messagebox(0,'裝載屏幕取詞動態鏈接庫函數: BL_SetFlag32失敗!','信息',MB_OK or MB_APPLMODAL or MB_ICONWARNING); result := false; exit; end;

@BL_GetText32 := GetProcAddress(g_hGetWordInst,'BL_GetText32'); if @BL_GetText32=nil then begin messagebox(0,'裝載屏幕取詞動態鏈接庫函數: BL_GetText32失敗!','信息',MB_OK or MB_APPLMODAL or MB_ICONWARNING); result := false; exit; end;

@SetNHW32 := GetProcAddress(g_hGetWordInst,'SetNHW32'); if @SetNHW32=nil then begin messagebox(0,'裝載屏幕取詞動態鏈接庫函數: SetNHW32失敗!','信息',MB_OK or MB_APPLMODAL or MB_ICONWARNING); result := false; exit; end;

@ResetNHW32 := GetProcAddress(g_hGetWordInst,'ResetNHW32'); if @ResetNHW32=nil then begin messagebox(0,'裝載屏幕取詞動態鏈接庫函數: ResetNHW32失敗!','信息',MB_OK or MB_APPLMODAL or MB_ICONWARNING); result := false; exit; end;

if SetNHW32()=false then begin messagebox(0,'無法設置屏幕取詞!','信息',MB_OK or MB_APPLMODAL or MB_ICONWARNING); result := false; exit; end;

result := true; end;

end.

鉤子 unit UnitHookDll;

interface

uses Windows, SysUtils, Classes, math, messages, dialogs, UnitNt2000Hook, UnitHookType;

const COLOR1 = 255; COLOR2 = 0; COLOR3 = 255; Trap = true; //True陷阱式,False表示改引入表式

procedure StartHook; stdcall;
procedure StopHook; stdcall;

implementation

var MouseHook: THandle; pShMem: PShareMem; hMappingFile: THandle; FirstProcess: Boolean;{是否是第一個進程} Hook: array[fBeginPaint..fDrawTextW] of THookClass;{API HOOK類} i:integer;

{自定義的BeginPaint} function NewBeginPaint(Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall; type TBeginPaint = function(Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall; begin Hook[fBeginPaint].Restore; Result := TBeginPaint(Hook[fBeginPaint].OldFunction)(Wnd, lpPaint); if Wnd = pshmem^.hHookWnd then{如果是當前鼠標的窗口句柄} begin pshmem^.DCMouse := result;{記錄它的返回值} end else pshmem^.DCMouse := 0; Hook[fBeginPaint].Change; end;

{自定義的GetWindowDC} function NewGetWindowDC(Wnd: HWND): HDC; stdcall; type TGetWindowDC = function (Wnd: HWND): HDC; stdcall; begin Hook[fGetWindowDC].Restore; result := TGetWindowDC(Hook[fGetWindowDC].OldFunction)(Wnd); if Wnd = pshmem^.hHookWnd then{如果是當前鼠標的窗口句柄} begin pshmem^.DCMouse := result;{記錄它的返回值} end else pshmem^.DCMouse := 0; Hook[fGetWindowDC].Change; end;

{自定義的GetDC} function NewGetDC(Wnd: HWND): HDC; stdcall; type TGetDC = function (Wnd: HWND): HDC; stdcall; begin Hook[fGetDC].Restore; result := TGetDC(Hook[fGetDC].OldFunction)(Wnd); if Wnd = pshmem^.hHookWnd then{如果是當前鼠標的窗口句柄} begin pshmem^.DCMouse := result;{記錄它的返回值} end else pshmem^.DCMouse := 0; Hook[fGetDC].Change; end;

{自定義的CreateCompatibleDC} function NewCreateCompatibleDC(DC: HDC): HDC; stdcall; type TCreateCompatibleDC = function (DC: HDC): HDC; stdcall; begin Hook[fCreateCompatibleDC].Restore; result := TCreateCompatibleDC(Hook[fCreateCompatibleDC].OldFunction)(DC); if DC = pshmem^.DCMouse then{如果是當前鼠標的窗口HDC} begin pshmem^.DCCompatible := Result;{記錄它的返回值} end else pshmem^.DCCompatible := 0; Hook[fCreateCompatibleDC].Change; end;

function NewTextOutA(theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool; stdcall; type TTextOutA = function (theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;stdcall; var dwBytes: DWORD; poOri, poDC, poText, poMouse: TPoint; Size: TSize; Rec: TRect; faint: Boolean; begin Hook[fTextOutA].Restore;{暫停截取API,恢復被截的函數} try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := nXStart;{顯示的相對座標} poDC.y := nYStart; if(poOri.X = 0) and (poOri.Y = 0) then{如果HDC的座標爲(0,0)} begin if (theDC = pShmem^.DCCompatible) then faint := False{精確匹配,就是指定的內存HDC} else faint := True;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd,Rec); poOri.X := Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y := Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint := False;{精確匹配,是普通HDC} end; {計算顯示文字的屏幕座標} poText.x := poDC.x + poOri.x; poText.y := poDC.y + poOri.y; {獲取當前鼠標的座標} GetCursorPos(poMouse); {如果對齊屬性是居中} if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then begin GetCurrentPositionEx(theDC, @poOri); poText.x := poText.x + poOri.x; poText.y := poText.y + poOri.y; end; {顯示文字的長和寬} GetTextExtentPoint(theDC, Str, Count, Size); {鼠標是否在文本的範圍內} if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx) and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy) then begin {最多取MaxStringLen個字節} dwBytes := min(Count, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text), Str, dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutA, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text)<>#3)and(not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TTextOutA(Hook[fTextOutA].OldFunction)(theDC, nXStart, nYStart, str, count); end; Hook[fTextOutA].Change;{重新截取API} end;

function NewTextOutW(theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall; type TTextOutW=function (theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall; var dwBytes: DWORD; poOri, poDC, poText, poMouse: TPoint; Size: TSize; Rec:TRect; faint:boolean; begin Hook[fTextOutW].Restore;{暫停截取API,恢復被截的函數} // SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3)); try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := nXStart;{顯示的相對座標} poDC.y := nYStart; if(poOri.X=0)and(poOri.Y=0)then{如果HDC的座標爲(0,0)} begin if (theDC = pShmem^.DCCompatible)then faint := False{精確匹配,就是指定的內存HDC} else faint := True;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd,Rec); poOri.X := Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y := Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint := False;{精確匹配,是普通HDC} end; {計算顯示文字的屏幕座標} poText.x := poDC.x + poOri.x; poText.y := poDC.y + poOri.y; {獲取當前鼠標的座標} GetCursorPos(poMouse); {如果對齊屬性是居中} if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then begin GetCurrentPositionEx(theDC, @poOri); poText.x := poText.x + poOri.x; poText.y := poText.y + poOri.y; end; {顯示文字的長和寬} GetTextExtentPointW(theDC, Str, Count, Size); {鼠標是否在文本的範圍內} if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx) and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy) then begin {最多取MaxStringLen個字節} dwBytes := min(Count*2, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutW, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text)<>#3)and(not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TTextOutW(Hook[fTextOutW].OldFunction)(theDC, nXStart, nYStart, str, Count); end; Hook[fTextOutW].Change;{重新截取API} end;

function NewExtTextOutA(theDC: HDC; nXStart, nYStart: integer; toOptions:Longint; rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall; type TExtTextOutA=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint; rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall; var dwBytes: DWORD; poOri, poDC, poText, poMouse: TPoint; Size: TSize; Rec:TRect; faint:boolean; begin Hook[fExtTextOutA].Restore;{暫停截取API,恢復被截的函數} // SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3)); try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := nXStart;{顯示的相對座標} poDC.y := nYStart; if(poOri.X=0)and(poOri.Y=0)then{如果HDC的座標爲(0,0)} begin if (theDC=pShmem^.DCCompatible)then faint:=false{精確匹配,就是指定的內存HDC} else faint:=true;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd,Rec); poOri.X:=Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y:=Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint:=false;{精確匹配,是普通HDC} end; {計算顯示文字的屏幕座標} poText.x := poDC.x + poOri.x; poText.y := poDC.y + poOri.y; {獲取當前鼠標的座標} GetCursorPos(poMouse); {如果對齊屬性是居中} if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then begin GetCurrentPositionEx(theDC, @poOri); poText.x := poText.x + poOri.x; poText.y := poText.y + poOri.y; end; {顯示文字的長和寬} GetTextExtentPoint(theDC, Str, Count, Size); {鼠標是否在文本的範圍內} if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx) and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy) then begin {最多取MaxStringLen個字節} dwBytes := min(Count, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text), Str, dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutA, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text)<>#3)and(not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TExtTextOutA(Hook[fExtTextOutA].OldFunction)(theDC, nXStart, nYStart, toOptions, rect, Str, Count, Dx); end; Hook[fExtTextOutA].Change;{重新截取API} end;

function NewExtTextOutW(theDC: HDC; nXStart, nYStart: integer; toOptions: Longint; rect: PRect; Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall; type TExtTextOutW=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint; rect: PRect; Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall; var dwBytes: DWORD; poOri, poDC, poText, poMouse: TPoint; Size: TSize; Rec:TRect; faint:boolean;
begin Hook[fExtTextOutW].Restore;{暫停截取API,恢復被截的函數} // SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3)); try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := nXStart;{顯示的相對座標} poDC.y := nYStart; if(poOri.X=0)and(poOri.Y=0)then{如果HDC的座標爲(0,0)} begin if (theDC=pShmem^.DCCompatible)then faint:=false{精確匹配,就是指定的內存HDC} else faint:=true;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd,Rec); poOri.X:=Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y:=Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint:=false;{精確匹配,是普通HDC} end; {計算顯示文字的屏幕座標} poText.x := poDC.x + poOri.x; poText.y := poDC.y + poOri.y; {獲取當前鼠標的座標} GetCursorPos(poMouse); {如果對齊屬性是居中} if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then begin GetCurrentPositionEx(theDC, @poOri); poText.x := poText.x + poOri.x; poText.y := poText.y + poOri.y; end; {顯示文字的長和寬} GetTextExtentPointW(theDC, Str, Count, Size); {鼠標是否在文本的範圍內} if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx) and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy) then begin {最多取MaxStringLen個字節} dwBytes := min(Count*2, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutW, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text)<>#3)and(not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TExtTextOutW(Hook[fExtTextOutW].OldFunction)(theDC, nXStart, nYStart, toOptions,Rect, Str, Count, Dx); end; Hook[fExtTextOutW].Change;{重新截取API} end;

function NewDrawTextA(theDC: HDC; lpString: PAnsiChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall; type TDrawTextA=function (theDC: HDC; lpString: PAnsiChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall; var poMouse,poOri,poDC: TPoint; dwBytes: integer; RectSave,rec:TRect; faint:boolean;
begin Hook[fDrawTextA].Restore;{暫停截取API,恢復被截的函數} // SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3)); try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := 0;{局部邏輯座標初始化爲(0,0)} poDC.y := 0; if(poOri.X = 0) and (poOri.Y = 0)then{如果HDC的座標爲(0,0)} begin if (theDC = pShmem^.DCCompatible)then faint := False{精確匹配,就是指定的內存HDC} else faint := True;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd, Rec); poOri.X := Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y := Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint := False;{精確匹配,是普通HDC} end; RectSave := lpRect;{顯示的矩形} OffsetRect(RectSave, poOri.x+poDC.x, poOri.y + poDC.y);{顯示的矩形加上偏移} {獲取當前鼠標的座標} GetCursorPos(poMouse); {鼠標是否在文本的範圍內} if PtInRect(RectSave, poMouse) then begin if nCount = -1 then begin strcopy(@(pShMem^.Text[0]), lpString); end else begin {最多取MaxStringLen個字節} dwBytes := min(nCount, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text[0]), lpString, dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); end; {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextA, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text) <> #3) and (not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TDrawTextA(Hook[fDrawTextA].OldFunction)(theDC, lpString, nCount, lpRect, uFormat); end; Hook[fDrawTextA].Change;{重新截取API} end;

function NewDrawTextW(theDC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall; type TDrawTextW=function (theDC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall; var poMouse,poOri,poDC: TPoint; dwBytes: integer; RectSave,rec:TRect; faint:boolean; begin Hook[fDrawTextW].Restore;{暫停截取API,恢復被截的函數} // SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3)); try if pShMem^.bCanSpyNow then{是否開始取詞} begin GetDCOrgEx(theDC, poOri);{HDC的座標} poDC.x := 0;{局部邏輯座標初始化爲(0,0)} poDC.y := 0; if(poOri.X=0)and(poOri.Y=0)then{如果HDC的座標爲(0,0)} begin if (theDC=pShmem^.DCCompatible)then faint:=false{精確匹配,就是指定的內存HDC} else faint:=true;{模糊匹配,"可能"是內存HDC} {取鼠標當前處的窗口(等效於Delphi的控件)座標} GetWindowRect(pShMem^.hHookWnd,Rec); poOri.X:=Rec.Left;{把窗口座標作爲HDC的座標} poOri.Y:=Rec.Top; end else begin{如果是普通HDC} {局部邏輯座標轉化爲設備相關座標} LPToDP(theDC, poDC, 1); faint:=false;{精確匹配,是普通HDC} end; RectSave := lpRect;{顯示的矩形} OffsetRect(RectSave, poOri.x+poDC.x, poOri.y+poDC.y);{顯示的矩形加上偏移} {獲取當前鼠標的座標} GetCursorPos(poMouse); {鼠標是否在文本的範圍內} if PtInRect(RectSave, poMouse) then begin if nCount=-1 then begin strcopy(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString))); end else begin {最多取MaxStringLen個字節} dwBytes := min(nCount*2, MaxStringLen); {拷貝字符串} CopyMemory(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString)), dwBytes); {以空字符結束} pShMem^.Text[dwBytes] := Chr(0); end; {發送WM_MOUSEPT成功取詞的消息給主程序} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2); {如果輸出的不是Tab鍵,而且是精確匹配的} if (string(pShMem^.Text)<>#3)and(not faint) then pShMem^.bCanSpyNow := False;{取詞結束} end; end; finally {調用被截的函數} result := TDrawTextW(Hook[fDrawTextW].OldFunction)(theDC, lpString, nCount, lpRect, uFormat); end; Hook[fDrawTextW].Change;{重新截取API} end;

{遍歷所有菜單項} procedure IterateThroughItems(WND:HWND;menu:Hmenu;p:TPoint;Level:integer); var i:integer; info:TMenuItemInfo; rec:TRect; begin for i:=0 to GetMenuItemCount(menu)-1 do {遍歷所有子菜單項} begin fillchar(info,sizeof(info),0); info.cbSize:=sizeof(info); info.fMask:=MIIM_TYPE or MIIM_SUBMENU; info.cch:=256; getmem(info.dwTypeData,256); {取菜單的文字} GetMenuItemInfo(menu,i,true,info); {取菜單的座標} GetMenuItemRect(wnd,menu,i,rec); {如果鼠標在菜單的矩形區域內} if (rec.Left<=p.X)and(p.X<=rec.Right)and(rec.Top<=p.Y)and(p.Y<=rec.Bottom)then if (info.cch<>0) then begin {取出菜單文字} strlcopy(pShMem^.Text,info.dwTypeData,min(info.cch,MaxStringLen)); pShMem^.bCanSpyNow := False; {發送WM_MOUSEPT成功取詞的消息給主程序} PostMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2); end; // freemem(info.dwTypeData,256); // info.dwTypeData:=nil; if info.hSubMenu<>0 then {如果它有下級子菜單,則歸遞調用} begin IterateThroughItems(wnd,info.hSubMenu,p,Level+1); end; end; end;

{定時器,每10毫秒被調用一次} procedure fOnTimer(theWnd: HWND; msg, idTimer: Cardinal; dwTime: DWORD); stdcall; var InvalidRect: TRECT; buffer:array[0..256]of char; menu:Hmenu; MousePoint:TPoint; begin pShMem^.nTimePassed := pShMem^.nTimePassed + 1; if pShMem^.nTimePassed = 20 then {如果鼠標停留了0.1秒} begin MousePoint:=pshmem^.pMouse; {獲取當前鼠標所在的窗口(等效於Delphi的控件)句柄} pshmem^.hHookWnd := WindowFromPoint(MousePoint); {屏幕座標轉換爲窗口(等效於Delphi的控件)客戶區的座標} ScreenToClient(pshmem^.hHookWnd, MousePoint); pShMem^.bCanSpyNow := true;{可以開始取詞} {如果客戶區的座標爲負值,則說明鼠標位於菜單或標題的上空} if(MousePoint.x<0)or(MousePoint.y<0) then begin {讀取並設置標題,讓其重繪} Getwindowtext(pshmem^.hHookWnd,buffer,sizeof(buffer)-1); Setwindowtext(pshmem^.hHookWnd,pchar(string(buffer)+' ')); Setwindowtext(pshmem^.hHookWnd,buffer); {客戶區的座標恢復爲屏幕座標} ClientToScreen(pshmem^.hHookWnd, MousePoint); {取出當前的菜單} menu:=GetMenu(pshmem^.hHookWnd); if menu<>0 then {遍歷所有菜單,判斷是否位於鼠標的下方} IterateThroughItems(pshmem^.hHookWnd,menu,MousePoint,1); end else begin{否則,說明鼠標位於客戶區} InvalidRect.left := MousePoint.x; InvalidRect.top := MousePoint.y; InvalidRect.Right := MousePoint.x + 1; InvalidRect.Bottom := MousePoint.y + 1; {重繪客戶區} InvalidateRect(pshmem^.hHookWnd, @InvalidRect, false); end; end else if pShMem^.nTimePassed >= 30 then begin pShMem^.nTimePassed := 30; end; {清空pShmem} end;

{鼠標鉤子} function MouseHookProc(nCode: integer; wPar: WParam; lPar: LParam): lResult; stdcall; var pMouseInf: TMouseHookStruct; begin pShMem^.nTimePassed := 0; if (nCode >= 0) and ((wPar = WM_MOUSEMOVE)or(wPar = WM_NCMOUSEMOVE)) then begin pMouseInf := (PMouseHookStruct(lPar))^; if (pShMem^.pMouse.x <> pMouseInf.pt.x) or (pShMem^.pMouse.y <> pMouseInf.pt.y) then begin if nCode = HC_NOREMOVE then pShMem^.fStrMouseQueue := 'Not removed from the queue' else pShMem^.fStrMouseQueue := 'Removed from the queue'; {鼠標的座標} pShMem^.pMouse := pMouseInf.pt; {鼠標所在的窗口} pShMem^.hHookWnd := pMouseInf.hwnd; {1是自定義的數值,表明這是鼠標消息} postMessage(pShMem^.hProcWnd, WM_MOUSEPT, 1, 1); end; end; Result := CallNextHookEx(MouseHook, nCode, wPar, lPar); end;

{開始取詞} procedure StartHook; stdcall; begin if MouseHook=0 then begin pShMem^.fTimerID := SetTimer(0, 0, 10, @fOnTimer); {注入其它進程} MouseHook := SetWindowsHookEx(WH_MOUSE, MouseHookProc, HInstance, 0); end; end;

{停止取詞} procedure StopHook; stdcall; begin if MouseHook<>0 then begin KillTimer(0, pShMem^.fTimerID); UnhookWindowsHookEx(MouseHook); MouseHook:=0; end; end;

initialization hMappingFile := OpenFileMapping(FILE_MAP_WRITE,False,MappingFileName); if hMappingFile=0 then begin hMappingFile := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShareMem),MappingFileName); FirstProcess := True; {這是第一個進程,即主程序} end else FirstProcess := False; if hMappingFile = 0 then Exception.Create('不能建立共享內存!');

pShMem := MapViewOfFile(hMappingFile,FILE_MAP_WRITE or FILE_MAP_READ,0,0,0); if pShMem = nil then begin CloseHandle(hMappingFile); Exception.Create('不能映射共享內存!'); end; if FirstProcess then begin pShMem^.bCanSpyNow:=false; end; Hook[fBeginPaint] := THookClass.Create(Trap,@BeginPaint,@NewBeginPaint);{Trap=True陷阱式} Hook[fGetWindowDC] := THookClass.Create(Trap,@GetWindowDC,@NewGetWindowDC); Hook[fGetDC] := THookClass.Create(Trap,@GetDC,@NewGetDC); Hook[fCreateCompatibleDC] := THookClass.Create(Trap,@CreateCompatibleDC,@NewCreateCompatibleDC); Hook[fTextOutA] := THookClass.Create(Trap,@TextOutA,@NewTextOutA); Hook[fTextOutW] := THookClass.Create(Trap,@TextOutW,@NewTextOutW); Hook[fExtTextOutA] := THookClass.Create(Trap,@ExtTextOutA,@NewExtTextOutA); Hook[fExtTextOutW] := THookClass.Create(Trap,@ExtTextOutW,@NewExtTextOutW); Hook[fDrawTextA] := THookClass.Create(Trap,@DrawTextA,@NewDrawTextA); Hook[fDrawTextW] := THookClass.Create(Trap,@DrawTextW,@NewDrawTextW); finalization for i := Low(hook) to High(hook) do if Hook[i]<>nil then Hook[i].Destroy; UnMapViewOfFile(pShMem); {取消映射視圖} CloseHandle(hMappingFile); {關閉映射文件句柄} end.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章