软件名称: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++相似的软件就算大功告成了! |
|