要建个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.
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.