分享

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

 饮冰E士 2013-09-28
 
 
软件名称: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条评论

    发表

    请遵守用户 评论公约

    类似文章 更多