C# 自己动手实现Spy++(一)
2013-09-01 14:32
363 查看
因为项目要用到获取其他程序的标题,就想到了用Spy++,但是它是一个工具,并没有C#的源代码,所以就想探索下他的原理,网上搜索了下spy++的源代码,找到了一篇:/article/8930046.html,是用VC写的,又从CSDN下载了一个资源:http://download.csdn.net/detail/zjhzznzlx/2720998#comment,发现是用C#写的,就打开看看,就找到了关键的几句:
IntPtr hWnd = Win32.WindowFromPoint(Cursor.Position); //最关键的一句
if (OldWnd != IntPtr.Zero && OldWnd != hWnd)
{
Refresh(OldWnd); //erase old window
}
if (hWnd == IntPtr.Zero)
{
textBox1.Text = null;
textBox2.Text = null;
textBox3.Text = null;
textBox4.Text = null;
textBox5.Text = null;
}
else
{
OldWnd = hWnd;
textBox1.Text = string.Format("{0}", hWnd.ToInt32().ToString());
textBox3.Text = this.GetClassName(hWnd);
textBox2.Text = this.GetWindowText(hWnd);
Win32.GetWindowInfo (hWnd,ref win);
textBox4.Text =win.exStyle .ToString ();
Win32.Rect rc = new Win32.Rect();
Win32.GetWindowRect(hWnd, ref rc);
textBox5.Text = string.Format("[{0} x {1}], ({2},{3})-({4},{5})", rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top, rc.right, rc.bottom);
this.Highlight(hWnd);
}
其中第一句最重要:
ntPtr hWnd = Win32.WindowFromPoint(Cursor.Position);
,找到了句柄就可以根据句柄找到相关的窗口标题、类名、大小、坐标等信息。
发现他是引用了一个DLL:"win32GDI.dll",然后上网搜索并没有找到这个DLL,估计是作者自己封装的,然后就再找WindowFromPoint这个函数,这个函数根据名字就很好理解它的功能,就是根据坐标获取窗口,在网上找到了这个是windows的API函数,直接引用即可,只不过这个函数的原型为:
[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]//指定坐标处窗体句柄
public static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
这里面有两个参数,即X,Y坐标,作者那里把它改为一个参数point类型。
同理找到其他API函数原型:
[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]//指定坐标处窗体句柄
public static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
[DllImport("user32.dll")]
public extern static int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hwnd, ref Rectangle lpRect);
[DllImport("User32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool RedrawWindow(IntPtr hwnd, COMRECT rcUpdate, IntPtr hrgnUpdate, int flags);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool InvalidateRect(IntPtr hWnd, COMRECT rect, bool erase);
通过以上函数就可以实现获取窗口的句柄、标题、类型、大小、坐标等。然而实现高亮的时候代码还是有点问题:
public void Highlight(IntPtr hWnd) //高亮其实就是用Pen绘制一个和窗口大小一样的红色框
{
const float penWidth = 3;
Win32.Rect rc = new Win32.Rect();
Win32.GetWindowRect(hWnd, ref rc);
IntPtr hDC = Win32.GetWindowDC(hWnd);
if (hDC != IntPtr.Zero)
{
using (Pen pen = new Pen(Color.Red, penWidth))
{
using (Graphics g = Graphics.FromHdc(hDC))
{
Font font = new Font("Courer New", 9, FontStyle.Bold);
g.DrawRectangle(pen, 0, 0, rc.right - rc.left - (int)penWidth, rc.bottom - rc.top - (int)penWidth);
g.DrawString("BIC Tech <SPY>", font, Brushes.Red, 5, 5);
}
}
}
Win32.ReleaseDC(hWnd, hDC);
}
public void Highlight2(IntPtr hWnd) //我的代码,尚有问题
{
const float penWidth = 3;
Rectangle rc = new Rectangle();
GetWindowRect(hWnd, ref rc);
IntPtr hDC = GetWindowDC(hWnd);
if (hDC != IntPtr.Zero)
{
using (Pen pen = new Pen(Color.Red, penWidth))
{
using (Graphics g = Graphics.FromHdc(hDC))
{
Font font = new Font("Courer New", 9, FontStyle.Bold);
g.DrawRectangle(pen, 0, 0, rc.Right - rc.Left - (int)penWidth, rc.Bottom - rc.Top - (int)penWidth);
g.DrawString("BIC Tech <SPY>", font, Brushes.Red, 5, 5);
}
}
}
Win32.ReleaseDC(hWnd, hDC);
}
public void Refresh(IntPtr hWnd)
{
Win32.InvalidateRect(hWnd, IntPtr.Zero, 1 /* TRUE */);
Win32.UpdateWindow(hWnd);
Win32.RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, Win32.RDW_FRAME | Win32.RDW_INVALIDATE | Win32.RDW_UPDATENOW | Win32.RDW_ALLCHILDREN);
}
public void Refresh2(IntPtr hWnd) //我的代码,尚有问题
{
InvalidateRect(hWnd,new COMRECT(0,0,0,0),true);
UpdateWindow(hWnd);
RedrawWindow(hWnd, new COMRECT(0, 0, 0, 0), IntPtr.Zero, Win32.RDW_FRAME | Win32.RDW_INVALIDATE | Win32.RDW_UPDATENOW | Win32.RDW_ALLCHILDREN);
}
今天就暂时到这里,基本上实现了获取窗口的句柄、标题、类型、大小、坐标等功能,高亮功能留待后续研究。
代码下载地址:
http://download.csdn.net/detail/xtfnpgy/5862401
开发环境:VS2008
相关文章推荐
- C# 自己动手实现Spy++(二)
- 自己动手实现一个C#中List
- 验证码识别实践2:自己动手C#实现,对CSDN资源上传验证码识别率100%,久游网登陆90%
- C# :自己动手实现:使用数组的方式实现List
- 验证码识别实践1:自己动手C#实现
- 自己动手实现网络服务器(Web Server)——基于C#
- 验证码识别实践2:自己动手C#实现,对CSDN资源上传验证码识别率100%,久游网登陆90%
- 验证码识别实践3:自己动手C#实现,颜色差异法去除干扰线
- 验证码识别实践3:自己动手C#实现,颜色差异法去除干扰线
- 验证码识别实践3:自己动手C#实现,颜色差异法去除干扰线
- C#中自己动手创建一个Web Server(非Socket实现)
- C#中自己动手创建一个Web Server(非Socket实现)
- 自己动手写Redis客户端(C#实现)3 - GET请求和批量回复
- 自己动手写Redis客户端(C#实现)4 - 整数回复
- 验证码识别实践1:自己动手C#实现
- 自己动手写Redis客户端(C#实现)2 - SET请求和状态回复(set)
- 自己动手实现操作系统引导程序(OS bootloader)——借助QEMU/GDB/losetup/dd等工具
- C#基础系列:实现自己的ORM(构造我自己的ORM)
- 自己动手用c#写控件(上)
- 自己动手实现简易的div可编辑富文本框及按下tab键后增加4个空格功能