屏幕取词实现

要建个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.
 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
 GetWord是一款专业的屏幕取词组件(控件),它可以帮助您在公司产品中快速便捷地集成屏幕取词功能,有效降低软件开发成本。目前,遍布世界各地的50多个国家和地区的众多客户都在使用GetWord。这些客户有:Apple(美国)、LEC(美国)、NetBrain(美国)、Autonomy(英国)、MJT Net(英国)、Linguatec(德国)、Issendis(法国)、Karolinska Insitutet(瑞典)、Caliber Multimedia(台湾)、MegaDict(泰国)、Matrix Development System(西班牙)、国泰君安(中国上海)等等. 产品信息: 支持的操作系统: Windows 2000/Windows XP/Windows Server 2003/Windows Vista/windows 7支持的软件开发环境: GetWord支持所有主流的软件开发环境,如Visual Studio 6.0, Visual Studio .Net 2003, Visual Studio .Net 2005, Delphi , C++ Builder, Dev-Cpp等等。主要功能特征:1. 支持英文, 简体中文, 繁体中文, 俄语, 法语, 日语, 德语, 西班牙语, 阿拉伯语, 朝鲜语, 土耳其语, 瑞典语, 挪威语, 意大利语, 拉丁语, 葡萄牙语, 波兰语, 印度语, 泰国语, 越南语等所有常见语言编码格式.2. 支持Unicode.3. 支持语境信息提取和整句提取,不仅可取到光标所在处的词,还可以取到其前后的词,便于智能识别和分析.4. 支持区域抓取,可以抓取到给定区域内的所有文字(一行或多行).5. 支持Adobe Acrobat, Acrobat Reader的PDF屏幕取词(已集成Adobe商用数字证书,该证书Adobe售价2500美金).6. 支持选择取词(亦称高亮取词,划词取词).7. 支持命令行(Command Prompt)取词.8. 支持各种标准Windows组件,如对话框、工具栏、菜单、编辑框、组合框、列表框、树型控件等.9. 支持各种常见办公软件,如微软Office、Outlook Express等.10. 支持各种常见浏览器,如IE、FireFox、Mozilla、MyIE、Netscape等.11. 支持鼠标取词、热键取词等多种取词模式. 支持ActiveX、Raw Dll等多种调用接口.12. 封装程度高,使用方便,向现有应用程序中添加屏幕取词支持一般只需要十几行语句即可. 公司名称:北京如令科技有限公司 公司网址 下载地址: http://www.textcapture.com/software/getword.zip 销售热线:010-88135135 QQ:184755771

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值