分享

用Delphi做一个组件探测器:WidgetSpy

 饮冰E士 2013-09-30

用Delphi做一个组件探测器:WidgetSpy

 

 

软件名称:WidgetSpy

功能描述:探测系统运行程序界面中组件、窗口的基本信息:

     1、所测组件的类名;

     2、所测组件的句柄;

     3、所测组件的进程ID;

     4、所测组件的标题或文本内容;

     5、所测组件的父句柄;

     6、所测组件所在程序的名称及路径。

开发工具:Delphi7.0

三方控件:无(全部使用Delphi自带控件完成)

所需资源:定制资源文件,包含2个图标文件(默认图标、鼠标指针拖走后的图标 

)、1个鼠标指针。

 

 

实现方法:

 

  一、获取光标所在点的句柄

  要想知道目标组件的基本信息,必须要先获取它的句柄。有了句柄,就可以进 

行各种各样的操作,以及进一步得到更加丰富的相关信息。方法如下:

var

  hWnd: THandle;

begin

  hWnd := WindowFromPoint(Sender);   // windowfrompoint 获得窗口指定点的 

句柄

end;

 

  二、根据句柄获取相关参数

var

  hWnd: THandle;

  Buf: array[0..1024] of Char;

begin

  hWnd := WindowFromPoint(Sender);

  //显示目标的句柄:

  edit2.Text := IntToStr(hWnd);

  //显示父句柄:

  edit5.Text:=IntToStr(GetParent(hWnd));

  //获取类名:

  if boolean(GetClassName(hWnd,Buf,1024)) then

    edit1.Text := string(Buf)

  else edit1.Text := ’’(没找到!)’’;

 

  flashwindow(hWnd,true);  //窗口标题栏闪烁

 

  //获取线程ID:

  GetWindowThreadProcessId(hwnd,@pid);

  edit3.Text := IntToStr(pid);

  //获取标题或文本内容:

  //GetWindowText(hWnd,Buf,256);//方法一、不能获取外部程序文本框的内容( 

不好)

  SendMessage(hWnd, WM_GETTEXT, 1024, Integer(@Buf)); //方法二、发送消息 

获取控件文本(好)

  edit4.Text := Buf;

 

  三、根据进程ID取得目标程序

  由于目标组件所在的程序,不能根据组件的句柄获取,因此要先通过目标句柄 

获取进程ID,再根据进程ID来获取目标所在的应用程序。可通过下面的函数来实现 

//根据进程名,得到程序的路径(uses psapi)

function TFrmMain.GetProcessPath(ProcessID: DWORD): string;

var

  Hand: THandle;

  ModName: Array[0..Max_Path-1] of Char;

  hMod: HModule;

  n: DWORD;

begin

  Result:=’’’’;

  Hand:=OpenProcess(PROCESS_QUERY_INFORMATION or  

PROCESS_VM_READ,False,ProcessID);

  if Hand>0 then

  try

    ENumProcessModules(Hand,@hMod,Sizeof(hMod),n);

    if GetModuleFileNameEx(Hand,hMod,ModName,Sizeof(ModName))>0 then

    //Result:=ExtractFilePath(ModName);//目标程序所在路径

    Result:=ModName;                   //目标程序

  except

  end;

end;

 

  四、触发探测事件的机制

  主要是通过判断鼠标左键是否按下来触发,当鼠标左键铵下时,开始探测光标 

所在位置的组件;当鼠标左键释放时,停止探测。可以用两种方法来实现:

  1、用一个Timer控件来监测,通过循环扫描鼠标左键的状态来进行判断;

  2、在主窗体中放一可视控件(如Image),让在该控件上铵住鼠标左键,激活 

探测事件后再移动到目标区域进行探测。放开鼠标左键即结束探测。

  本软件使用第二种方法。Image控件在未探测时显示默认的图标(其中有一个 

鼠标指针的图案);当探测事件激活后,Image控件显示另外一个图标(其中没有 

鼠标指针的图案),同时将系统的鼠标指针更换为自定义的形状(即包含在默认图 

标中的指针图案)。这样可以让人觉得系统鼠标的指针图案是从Image控件的默认 

图标中取下来的这样一种假象。

 

  五、开始探测组件

  该功能在Image控件的OnMouseDown事件中触发。代码如下:

var

  myICN:TIcon;//设为全局变量,在程序退出时myICN.Free;

procedure TFrmMain.Image1MouseDown(Sender: TObject; Button:  

TMouseButton;

  Shift: TShiftState; X, Y: Integer);

begin

  Timer1.Interval := 50;

  Timer1.Enabled:=true;

  SetSystemCursor(LoadCursor(HInstance, ’’mycur’’), ocr_normal); //改变系 

统鼠标形状

 

  myICN:=TIcon.Create;

  myICN.handle:=loadicon(hinstance,’’myIco1’’);

  Image1.Picture.Icon:=myICN;//更换为没有指针形象的图标

end;

 

  六、停止探测组件

  该功能在Image控件的OnMouseUp事件中触发。代码如下:

procedure TFrmMain.Image1MouseUp(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

begin

  SystemParametersinfo(SPI_SETCURSORS,0,nil,SPIF_SENDCHANGE); //恢复为系 

统默认鼠标

  Timer1.Enabled:=false;

 

  myICN:=TIcon.Create;

  myICN.handle:=loadicon(hinstance,’’myIco’’);

  Image1.Picture.Icon:=myICN;//更换为包含指针形象的图标

end;

 

  七、探测组件的实施

  探测组件的实施,就是当Timer控件开始计时起,循环对光标所在点进行探测 

的过程。代码如下:

procedure TFrmMain.Timer1Timer(Sender: TObject);

var mPos: TPoint;

begin

  if boolean(GetCursorPos(mPos)) then //getcursorPos函数获取光标位置,以 

屏幕坐标表示。

  GetMousePosInfo(mPos);  //调用自定义过程!

end;

综合上述功能,可以自定义一个过程GetMousePosInfo,用它来获取所有需要的信 

息:

//自定义过程,获取相关参数

procedure TFrmMain.GetMousePosInfo(Sender: TPoint);

var

  hWnd,pid: THandle;

  Buf: array[0..1024] of Char;

begin

  hWnd := WindowFromPoint(Sender);   // windowfrompoint 获得窗口指定点的 

句柄

  if chk2.Checked then edit2.Text :=IntToHex(hWnd,0)//转为16进制

  else edit2.Text := IntToStr(hWnd);        //默认为10进制

  if chk2.Checked then edit5.Text :=IntToHex(GetParent(hWnd),0)

  else edit5.Text:=IntToStr(GetParent(hWnd));

  if boolean(GetClassName(hWnd,Buf,1024)) then

    edit1.Text := string(Buf)

  else edit1.Text := ’’(没找到!)’’;

 

  flashwindow(hWnd,true);  //窗口标题栏闪烁

  GetWindowThreadProcessId(hwnd,@pid);

  if chk2.Checked then edit3.Text :=IntToHex(pid,0)

  else edit3.Text := IntToStr(pid);

  //GetWindowText(hWnd,Buf,256);//不能获取其他窗口文本框的内容

  SendMessage(hWnd, WM_GETTEXT, 1024, Integer(@Buf)); //发送消息获取控件 

文本

  edit4.Text := Buf;

  edit6.Text :=GetProcessPath(pid);

end;

 

这样,一个跟SPY ++相似的软件就算大功告成了!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多