博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

长征25000

----------人生就是一次长征,一次壮举,当我们回味的时候,是包含深情的。 这样的人生才算没有白过。。。。。。
changzheng.cublog.cn


鼠标取词代码

unit UnitHookType;
interface
uses windows, messages;
const
    MaxStringLen = 100;
    WM_MOUSEPT = WM_USER + 1138;
    MappingFileName = 'GetWord32 for 9x NT 2000';
    fBeginPaint=0;
    fGetWindowDC=1;
    fGetDC=2;
    fCreateCompatibleDC=3;
    fTextOutA=4;
    fTextOutW=5;
    fExtTextOutA=6;
    fExtTextOutW=7;
    fDrawTextA=8;
    fDrawTextW=9;
type
    PPointer = ^Pointer;
    TShareMem = packed record
        hProcWnd: HWND; {主应用窗口句柄}
        hHookWnd: HWND; {鼠标所在窗口}
        pMouse: TPoint; {鼠标信息}
        DCMouse,DCCompatible: HDC;
        fTimerID: integer;
        fStrMouseQueue: array[0..MaxStringLen] of Char; {鼠标信息串}
        nTimePassed: integer; {鼠标停留的时间}
        bCanSpyNow: Boolean; {开始取词}
        Text: array[0..MaxStringLen] of Char; {字符串}
    end;
    PShareMem = ^TShareMem;
implementation
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 = 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, 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 UnitNt2000Hook;
interface
uses classes, Windows,SysUtils, messages,dialogs;
type
  TImportCode = packed record
     JumpInstruction: Word;
     AddressOfPointerToFunction: PPointer;
  end;
  PImportCode = ^TImportCode;
  PImage_Import_Entry = ^Image_Import_Entry;
  Image_Import_Entry = record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: Word;
    MinorVersion: Word;
    Name: DWORD;
    LookupTable: DWORD;
  end;
  TLongJmp = packed record
     JmpCode: ShortInt; {指令,用$E9来代替系统的指令}
     FuncAddr: DWORD; {函数地址}
  end;
  THookClass = class
  private
     Trap:boolean; {调用方式:True陷阱式,False改引入表式}
     hProcess: Cardinal; {进程句柄,只用于陷阱式}
     AlreadyHook:boolean; {是否已安装Hook,只用于陷阱式}
     AllowChange:boolean; {是否允许安装、卸载Hook,只用于改引入表式}
     Oldcode: array[0..4]of byte; {系统函数原来的前5个字节}
     Newcode: TLongJmp; {将要写在系统函数的前5个字节}
  private
  public
     OldFunction,NewFunction:Pointer;{被截函数、自定义函数}
     constructor Create(IsTrap:boolean;OldFun,NewFun:pointer);
     constructor Destroy;
     procedure Restore;
     procedure Change;
  published
  end;
implementation
{取函数的实际地址。如果函数的第一个指令是Jmp,则取出它的跳转地址(实际地址),这往往是由于程
序中含有Debug调试信息引起的}
function FinalFunctionAddress(Code: Pointer): Pointer;
Var
  func: PImportCode;
begin
  Result:=Code;
  if Code=nil then exit;
  try
    func:=code;
    if (func.JumpInstruction=$25FF) then
      {指令二进制码FF 25  汇编指令jmp [...]}
      Func:=func.AddressOfPointerToFunction^;
    result:=Func;
  except
    Result:=nil;
  end;
end;
{更改引入表中指定函数的地址,只用于改引入表式}
function PatchAddressInModule(BeenDone:Tlist;hModule: THandle; OldFunc,NewFunc:
Pointer):integer;
const
   SIZE=4;
Var
   Dos: PImageDosHeader;
   NT: PImageNTHeaders;
   ImportDesc: PImage_Import_Entry;
   rva: DWORD;
   Func: PPointer;
   DLL: String;
   f: Pointer;
   written: DWORD;
   mbi_thunk:TMemoryBasicInformation;
   dwOldProtect:DWORD;
begin
  Result:=0;
  if hModule=0 then exit;
  Dos:=Pointer(hModule);
  {如果这个DLL模块已经处理过,则退出。BeenDone包含已处理的DLL模块}
  if BeenDone.IndexOf(Dos)>=0 then exit;
  BeenDone.Add(Dos);{把DLL模块名加入BeenDone}
  OldFunc:=FinalFunctionAddress(OldFunc);{取函数的实际地址}
  {如果这个DLL模块的地址不能访问,则退出}
  if IsBadReadPtr(Dos,SizeOf(TImageDosHeader)) then exit;
  {如果这个模块不是以'MZ'开头,表明不是DLL,则退出}
  if Dos.e_magic<>IMAGE_DOS_SIGNATURE then exit;{IMAGE_DOS_SIGNATURE='MZ'}
  {定位至NT Header}
  NT :=Pointer(Integer(Dos) + dos._lfanew);
  {定位至引入函数表}
  RVA:=NT^.OptionalHeader.
     DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  if RVA=0 then exit;{如果引入函数表为空,则退出}
  {把函数引入表的相对地址RVA转换为绝对地址}
  ImportDesc := pointer(DWORD(Dos)+RVA);{Dos是此DLL模块的首地址}
  {遍历所有被引入的下级DLL模块}
  While (ImportDesc^.Name<>0) do
  begin
    {被引入的下级DLL模块名字}
    DLL:=PChar(DWORD(Dos)+ImportDesc^.Name);
    {把被导入的下级DLL模块当做当前模块,进行递归调用}
    PatchAddressInModule(BeenDone,GetModuleHandle(PChar(DLL)),OldFunc,NewFunc);
    {定位至被引入的下级DLL模块的函数表}
    Func:=Pointer(DWORD(DOS)+ImportDesc.LookupTable);
    {遍历被引入的下级DLL模块的所有函数}
    While Func^<>nil do
    begin
      f:=FinalFunctionAddress(Func^);{取实际地址}
      if f=OldFunc then {如果函数实际地址就是所要找的地址}
      begin
         VirtualQuery(Func,mbi_thunk, sizeof(TMemoryBasicInformation));
         VirtualProtect(Func,SIZE,PAGE_EXECUTE_WRITECOPY,mbi_thunk.Protect);{更改内存属性}
         WriteProcessMemory(GetCurrentProcess,Func,@NewFunc,SIZE,written);{把新函数地址覆盖
它}
         VirtualProtect(Func, SIZE, mbi_thunk.Protect,dwOldProtect);{恢复内存属性}
      end;
      If Written=4 then Inc(Result);
//      else showmessagefmt('error:%d',[Written]);
      Inc(Func);{下一个功能函数}
    end;
    Inc(ImportDesc);{下一个被引入的下级DLL模块}
  end;
end;
{HOOK的入口,其中IsTrap表示是否采用陷阱式}
constructor THookClass.Create(IsTrap:boolean;OldFun,NewFun:pointer);
begin
   {求被截函数、自定义函数的实际地址}
   OldFunction:=FinalFunctionAddress(OldFun);
   NewFunction:=FinalFunctionAddress(NewFun);
   Trap:=IsTrap;
   if Trap then{如果是陷阱式}
   begin
      {以特权的方式来打开当前进程}
      hProcess := OpenProcess(PROCESS_ALL_ACCESS,FALSE, GetCurrentProcessID);
      {生成jmp xxxx的代码,共5字节}
      Newcode.JmpCode := ShortInt($E9); {jmp指令的十六进制代码是E9}
      NewCode.FuncAddr := DWORD(NewFunction) - DWORD(OldFunction) - 5;
      {保存被截函数的前5个字节}
      move(OldFunction^,OldCode,5);
      {设置为还没有开始HOOK}
      AlreadyHook:=false;
   end;
   {如果是改引入表式,将允许HOOK}
   if not Trap then AllowChange:=true;
   Change; {开始HOOK}
   {如果是改引入表式,将暂时不允许HOOK}
   if not Trap then AllowChange:=false;
end;
{HOOK的出口}
constructor THookClass.Destroy;
begin
   {如果是改引入表式,将允许HOOK}
   if not Trap then AllowChange:=true;
   Restore; {停止HOOK}
   if Trap then{如果是陷阱式}
      CloseHandle(hProcess);
end;
{开始HOOK}
procedure THookClass.Change;
var
   nCount: DWORD;
   BeenDone: TList;
begin
  if Trap then{如果是陷阱式}
  begin
    if (AlreadyHook)or (hProcess = 0) or (OldFunction = nil) or (NewFunction = nil) then
        exit;
    AlreadyHook:=true;{表示已经HOOK}
    WriteProcessMemory(hProcess, OldFunction, @(Newcode), 5, nCount);
  end
  else begin{如果是改引入表式}
       if (not AllowChange)or(OldFunction=nil)or(NewFunction=nil)then exit;
       BeenDone:=TList.Create; {用于存放当前进程所有DLL模块的名字}
       try
         PatchAddressInModule(BeenDone,GetModuleHandle(nil),OldFunction,NewFunction);
       finally
         BeenDone.Free;
       end;
  end;
end;
{恢复系统函数的调用}
procedure THookClass.Restore;
var
   nCount: DWORD;
   BeenDone: TList;
begin
  if Trap then{如果是陷阱式}
  begin
    if (not AlreadyHook) or (hProcess = 0) or (OldFunction = nil) or (NewFunction = nil)
then
        exit;
    WriteProcessMemory(hProcess, OldFunction, @(Oldcode), 5, nCount);
    AlreadyHook:=false;{表示退出HOOK}
  end
  else begin{如果是改引入表式}
    if (not AllowChange)or(OldFunction=nil)or(NewFunction=nil)then exit;
    BeenDone:=TList.Create;{用于存放当前进程所有DLL模块的名字}
    try
      PatchAddressInModule(BeenDone,GetModuleHandle(nil),NewFunction,OldFunction);
    finally
      BeenDone.Free;
    end;
  end;
end;
end.
//===============主窗口=====================
unit UnitMain;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,UnitHookType, ExtCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    procedure getMouseInfo(var theMess:TMessage); message WM_MOUSEPT;{处理WM_MOUSEPT}
  private
    hMapObj : THandle;
    pShMem : PShareMem;
    fWndClosed:boolean;{是否正在退出主程序}
    { Private declarations }
  public
    { Public declarations }
  end;
//  {未公开的函数,实现隐浮窗口}
//  procedure SwitchToThisWindow(wnd:Hwnd;Switch:BOOL);stdcall;external 'user32.dll';
  procedure StartHook; stdcall; external 'GetWordDll.DLL';
  procedure StopHook; stdcall; external 'GetWordDll.DLL';
var
  Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
  if button1.caption='取词' then
  begin
     StartHook;
     button1.caption:='停止';
  end
  else begin
     StopHook;
     button1.caption:='取词';
  end;
end;
const
  StrProcNames : array[fTextOutA..fDrawTextW+1] of String =
    ('来自TextOutA',
     '来自TextOutW',
     '来自ExtTextOutA',
     '来自ExtTextOutW',
     '来自DrawTextA',
     '来自DrawTextW',
     '来自菜单');
procedure TForm1.getMouseInfo(var theMess : TMessage);
begin
  if fWndClosed then
    Exit;
  if theMess.LParam = 1 then{显示鼠标位置}
{    Label1.caption := 'X:' + IntToStr(pShMem^.pMouse.x) + ' ' +
                        'Y:' + IntToStr(pShMem^.pMouse.y) + ' ' +
                        'HWND:0x' + IntToHex(pShMem^.hHookWnd, 8) + ' ' +
                        pShMem^.fStrMouseQueue }
  else if theMess.LParam = 2 then
  begin
    Label2.caption := pShMem^.Text;
    if (theMess.WParam>=0)and(theMess.WParam<=5) then
//        Label3.Caption :=StrProcNames[theMess.Wparam];
  end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  fWndClosed := True;{正在退出主程序}
  if button1.caption<>'取词' then
    Button1Click(sender);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  SetForegroundWindow(self.Handle);{实现隐浮窗口}
  hMapObj := OpenFileMapping(FILE_MAP_WRITE,{获取完全访问映射文件}
                             False,{不可继承的}
                             LPCTSTR(MappingFileName));{映射文件名字}
  if hMapObj = 0 then
  begin
    ShowMessage('不能定位内存映射文件块!');
    Halt;
  end;
  pShMem := MapViewOfFile(hMapObj,FILE_MAP_WRITE,0,0,0);
  if pShMem = nil then
  begin
    ShowMessage('映射文件错误'+ IntToStr(GetLastError));
    CloseHandle(hMapObj);
    Halt;
  end;
  FillChar(pShMem^, SizeOf(TShareMem), 0);
  pShMem^.hProcWnd := Self.Handle;
  fWndClosed:=false;
end;
initialization
finalization
end.
//========================================
 
  屏幕上的文字大都是由gdi32.dll的以下几个函数显示的:TextOutA、TextO
 
utW、ExtTextOutA、 
ExtTextOutW。实现屏幕抓词的关键就是截获对这些函数的调用,得到程序发给他
们的参数。  
  
  我的方法有以下三个步骤:  
  
  一、得到鼠标的当前位置  
  
  通过SetWindowsHookEx实现。  
  
  二、向鼠标下的窗口发重画消息,让它调用系统函数重画  
  
  通过WindowFromPoint,ScreenToClient,InvalidateRect 实现。  
  
  三、截获对系统函数的调用,取得参数(以TextOutA为例)  
  
  1.仿照TextOutA作成自己的函数MyTextOutA,与TextOutA有相同参数和返回
 
值,放在系统钩子所在 
的DLL里。  

 

发表于: 2006-11-28 ,修改于: 2006-11-28 13:55,已浏览2239次,有评论4条 推荐 投诉


网友评论
内容:
请问:GetWordDll.DLL 这个文件自么没有?
本站网友评论于:2007-10-05 14:29:48 (219.156.173.★)
内容:
似乎并不能用,调用该DLL时会出现应用程序初始化失败的错误。
本站网友评论于:2007-11-10 22:00:49 (220.112.195.★)
内容:
Delphi.下深入Windows核心编程.原书光盘代码.rar.rar
用emule 搜索,然后下载
本站网友评论于:2008-05-09 23:28:23 (60.184.155.★)
内容:
用emule 搜索,delphi.·±¥windows¨.pdf,然后下载
本站网友评论于:2008-05-09 23:39:37 (60.184.155.★)

发表评论