模仿VS编译器的Spy++
MySpy++
说明:
本例利用MFC模仿VS编译器的SPY++,通过捕捉工具,随着光标的移动可以获取到当前窗口的句柄、标题、类名、尺寸。
最终结果:
步骤:
1.打开资源视图-》Dialog,对对话框进行如下修改。
解析:
“搜索条件”是组合框,Group Box,可以任意拖动,选定包含区域。
“搜索条件”下面的文字和“句柄”、“标题”等都是Stati Text.
“捕捉工具图标”是picture control,同时还要改变相应的属性。Type选择Icon,Image选择对应的图标ID。
2.将要用到的资源(图标图、光标图)加载进来,或放入程序文件下的res文件。再放入到对应的变量中。
//加载捕捉工具移动前后的图标和光标
m_hNewIcon = AfxGetApp()->LoadIconW(IDI_ICON_BLANK);
m_hSpyIcon = AfxGetApp()->LoadIconW(IDI_ICON_TARGET);
m_hTargetCursor = AfxGetApp()->LoadCursorW(IDC_CRS_TARGET);
注意:在MFC中,要用AfxGetApp()去调用方式,不可以直接LoadIcon。
3捕捉工具。鼠标按下后图标、光标变化。
CRect rtTarget;
m_picTarget.GetWindowRect(&rtTarget);
ScreenToClient(&rtTarget);
SetCapture();
if (rtTarget.PtInRect(point))
{
m_picTarget.SetIcon(m_hNewIcon);
::SetCursor(m_hTargetCursor);
::SetCapture(m_hWnd);
bisDown = TRUE;
}
首先要获取picture control的大小,并判断光标是否在该区域。利用函数PtInRect()。
m_picTarget.GetWindowRect(&rtTarget);
rtTarget.PtInRect(point)
注意:
(1)一定要把屏幕坐标转换成客户区坐标。ScreenToClient(&rtTarget);
(2)SetCapture();作用:是将当前所有消息都交给当前窗口使用。
(3) ::双冒号,代表是全局函数,参数有相应的窗口句柄,等同于在WIN32的函数。
然后,把图标改成另一个空白图标,把光标改成圆形的光标。
4光标移动过程,找对应窗口的句柄。(有句柄就可以为所欲为了)
获取光标的位置:GetCursorPos(&ptMouse)
通过光标位置获取窗口句柄:hMyWnd=::WindowFromPoint(ptMouse);
5.鼠标弹起后的操作。
//捕捉结束后,把捕捉还原
m_picTarget.SetIcon(m_hSpyIcon);
ReleaseCapture();
bisDown = FALSE;
还原图标,同时还要释放ReleaseCapture(),而bisDown = FALSE是将光标还原,不再获取对应窗口的句柄。
注意:消息可以在类向导处添加。如:鼠标左键单击void CSpyDlg::OnLButtonDown(UINT nFlags, CPoint point)、鼠标移动void CSpyDlg::OnMouseMove(UINT nFlags, CPoint point)等消息。
以上的捕捉图标的难点就这些。下面的都是调用对应的API就可以完成了。
获取句柄并显示在编辑框中:
hMyWnd=::WindowFromPoint(ptMouse);
SetDlgItemText(IDC_EDT_HANDLE, str);
标题:
int nLen = ::GetWindowTextLength(hMyWnd);
if (nLen)
{
TCHAR* buf = new TCHAR[nLen + 1];
::GetWindowText(hMyWnd, buf, nLen + 1);
SetDlgItemText(IDC_EDT_TITAL, buf);
delete[] buf;
buf = NULL;
}
类名:
TCHAR* buf = new TCHAR[MAX_PATH];
if (buf)
{
::GetClassNameW(hMyWnd, buf, MAX_PATH);
SetDlgItemText(IDC_EDT_CLASS, buf);
delete[] buf;
buf = NULL;
}
尺寸:
CString str;
str.Format(L"(%d X %d)", rt.right-rt.left, rt.bottom-rt.top);
SetDlgItemText(IDC_EDT_SIZE, str);
注意:
(1)在边框中,可以显示文字、数字,但只能一次填入。要利用Format()进行格式转化,可以是十六进制、十进制、字符串等。记住:Format()是类CString的方法。
(2)尺寸处,可以不将屏幕坐标转化成客户区坐标,利用右下角坐标减去左上角坐标,可以获取窗口的高、宽。
源代码: 对话框的头文件。SpyDlg.h CStatic m_picTarget; //picture变量 HCURSOR m_hTargetCursor; //圆形光标 BOOL bisDown; //标记光标的使用情况 HICON m_hNewIcon, m_hSpyIcon; //点击捕捉工具前后,图标的变化 void GetHandle(HWND &hMyWnd); //获取句柄 void GetTitle(HWND &hMyWnd); //获取标题 void GetClass(HWND &hMyWnd); //获取类名 void GetSize(HWND &hMyWnd,RECT &rt);//获取尺寸
对话框的源文件. SpyDlg.cpp
初始化函数处:
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//加载捕捉工具移动前后的图标和光标
m_hNewIcon = AfxGetApp()->LoadIconW(IDI_ICON_BLANK);
m_hSpyIcon = AfxGetApp()->LoadIconW(IDI_ICON_TARGET);
m_hTargetCursor = AfxGetApp()->LoadCursorW(IDC_CRS_TARGET);对话框的源文件. SpyDlg.cpp
//鼠标按下消息 void CSpyDlg::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //当点击捕捉工具时,判断是否在捕捉区域,并改变光标 CRect rtTarget; m_picTarget.GetWindowRect(&rtTarget); ScreenToClient(&rtTarget); if (rtTarget.PtInRect(point)) { m_picTarget.SetIcon(m_hNewIcon); ::SetCursor(m_hTargetCursor); ::SetCapture(m_hWnd); bisDown = TRUE; } CDialogEx::OnLButtonDown(nFlags, point); } //鼠标移动消息 void CSpyDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //当鼠标移动时,找到不同窗口的句柄,并画出外边 POINT ptMouse; RECT rt; HDC hDeskDc; HWND hMyWnd; if (bisDown) { if (GetCursorPos(&ptMouse)) { hMyWnd=::WindowFromPoint(ptMouse); if (hMyWnd) { if (::GetWindowRect(hMyWnd, &rt)) { hDeskDc = ::GetDC(::GetDesktopWindow()); HPEN hPen = CreatePen(PS_SOLID, 5, RGB(0, 0, 255)); HPEN hOldPen = (HPEN)SelectObject(hDeskDc, hPen); //for (int i = 0; i < 10; ++i) //画边 { MoveToEx(hDeskDc, rt.left, rt.top, NULL); LineTo(hDeskDc, rt.right, rt.top); MoveToEx(hDeskDc, rt.right, rt.top, NULL); LineTo(hDeskDc, rt.right, rt.bottom); MoveToEx(hDeskDc, rt.right, rt.bottom, NULL); LineTo(hDeskDc, rt.left, rt.bottom); MoveToEx(hDeskDc, rt.left, rt.bottom, NULL); LineTo(hDeskDc, rt.left, rt.top); Sleep(100); } } } //分别显示窗口的句柄、标题、类名、尺寸 CSpyDlg::GetHandle(hMyWnd); CSpyDlg::GetTitle(hMyWnd); CSpyDlg::GetClass(hMyWnd); CSpyDlg::GetSize(hMyWnd, rt); } } CDialogEx::OnMouseMove(nFlags, point); } //鼠标弹起消息 void CSpyDlg::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //捕捉结束后,把捕捉还原 m_picTarget.SetIcon(m_hSpyIcon); ReleaseCapture(); bisDown = FALSE; CDialogEx::OnLButtonUp(nFlags, point); }
void CSpyDlg::GetHandle(HWND &hMyWnd) { CString str; if (hMyWnd) { str.Format(L"%08X", hMyWnd); SetDlgItemText(IDC_EDT_HANDLE, str); } else return ; } // void CSpyDlg::GetTitle(HWND &hMyWnd) { int nLen = ::GetWindowTextLength(hMyWnd); if (nLen) { TCHAR* buf = new TCHAR[nLen + 1]; ::GetWindowText(hMyWnd, buf, nLen + 1); SetDlgItemText(IDC_EDT_TITAL, buf); delete[] buf; buf = NULL; } else return ; } void CSpyDlg::GetClass(HWND &hMyWnd) { TCHAR* buf = new TCHAR[MAX_PATH]; if (buf) { ::GetClassNameW(hMyWnd, buf, MAX_PATH); SetDlgItemText(IDC_EDT_CLASS, buf); delete[] buf; buf = NULL; } else return; } void CSpyDlg::GetSize(HWND &hMyWnd,RECT &rt) { CString str; str.Format(L"(%d X %d)", rt.right-rt.left, rt.bottom-rt.top); SetDlgItemText(IDC_EDT_SIZE, str); }