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 = 10 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 >= 11 then
    begin
       pShMem
^.nTimePassed := 11;
    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, 11);
        end;
    end;
    Result :
= CallNextHookEx(MouseHook, nCode, wPar, lPar);
end;

{开始取词}
procedure StartHook; stdcall;
begin
   
if MouseHook=0 then
   begin
     pShMem
^.fTimerID := SetTimer(0010, @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.