因为项目要用到获取其他程序的标题,就想到了用Spy++,但是它是一个工具,并没有C#的源代码,所以就想探索下他的原理,网上搜索了下spy++的源代码,找到了一篇:http://blog.csdn.net/asanscape/article/details/2140176,是用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++(一)的更多相关文章

  1. C# 自己动手实现Spy++(二)

    昨天已经实现了获取窗口的标题.句柄等信息,但是高亮部分还有问题,而且红色绘制框擦除也有问题,今天就又研究了下上述两个问题. 高亮部分红色框只显示左上的边框,而右下的显示不出来,如图: 代码如下: pu ...

  2. 能动手绝不多说:开源评论系统remark42上手指南

    能动手绝不多说:开源评论系统 remark42 上手指南 前言 写博客嘛, 谁不喜欢自己倒腾一下呢. 从自建系统到 Github Page, 从 Jekyll 到 Hexo, 年轻的时候谁不喜欢多折腾 ...

  3. 动手做第一个Chrome插件

    Chrome插件是令人惊讶的简单,一旦你弄懂它的工作和实现原理.它是由一部分HTML,一部分Js,然后混合了一个叫做manifest.json的Json文件组合而成的整体.这意味着你可以使用你最擅长的 ...

  4. 浅谈Slick(2)- Slick101:第一个动手尝试的项目

    看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...

  5. 《动手实现一个网页加载进度loading》

    loading随处可见,比如一个app经常会有下拉刷新,上拉加载的功能,在刷新和加载的过程中为了让用户感知到 load 的过程,我们会使用一些过渡动画来表达.最常见的比如"转圈圈" ...

  6. Linux.NET实战手记—自己动手改泥鳅(上)

    各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...

  7. Hadoop2 自己动手编译Hadoop的eclipse插件

    前言:       毕业两年了,之前的工作一直没有接触过大数据的东西,对hadoop等比较陌生,所以最近开始学习了.对于我这样第一次学的人,过程还是充满了很多疑惑和不解的,不过我采取的策略是还是先让环 ...

  8. 自己动手,实现一种类似List<T>的数据结构(一)

    前言 上一篇文章<Unity3D中常用的数据结构总结与分析>简单总结了一下小匹夫工作中经常遇到的一些数据结构.不过小匹夫一直有种观点,就是光说的热闹实际啥也不做真的没啥意思.光说不练假把式 ...

  9. 自己动手,实现一种类似List<T>的数据结构(二)

    前言: 首先,小匹夫要祝各位看官圣诞快乐,新年愉快-.上一篇文章<自己动手,实现一种类似List<T>的数据结构(一)> 介绍了一下不依靠List<T>实现的各种接 ...

随机推荐

  1. Physics for Game Programmers (Grant Palmer 著)

    CHAPTER1 Adding Realism to Your Games CHAPTER2 Some Basic Concepts CHAPTER3 Basic Newtonian Mechanic ...

  2. docker nginx 运行后无法访问

    ## 1 最近在学docker部署,一开始打算将nginx先docker化的. 对照官方的docker镜像介绍说明,进行自定义配置 将官方的nginx.conf复制出来后,修改添加了一些自定义,主要是 ...

  3. idea+maven+springmvc+helloworld

    1.添加依赖,并在项目上添加Spring mvc框架的支持(add FrameWork Support): <dependency> <groupId>junit</gr ...

  4. antd 知识点

    表格实现:不管多少列,为列指定一个宽度,让表格在容器里可左右拖动 例子文件地址:https://github.com/cag2050/antd_mobx_demo/blob/master/src/co ...

  5. 关于 TypeReference 的解释

    首先 TypeReference  是描述 一个复杂 泛型的工具类. TypeReference 很多类库都有,用 fastjson 的 举例,大概就这个意思. 例子: Response<Fee ...

  6. PHP中strlen和mb_strlen的区别

    在PHP中,strlen与mb_strlen是求字符串长度的函数,下面通过例子,讲解这两者之间的区别. <?php //测试时文件的编码方式要是UTF8 $str='中文a字1符'; echo ...

  7. Elastic Story(一)

    关于_all 当索引一个文档的时候,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引.例如,当索引这个文档时: { "tweet": ...

  8. 怎么理解Python画图中的X,y

    X_outliers=np.array([[3.4, 1.3], [3.2, 0.8]]) y_outliers=np.array([0, 0]) 要明白X,y不再是我们高中时候学的x,y轴的坐标:首 ...

  9. java中length与length()

    length是对数组而言的,指的是数组的长度. length()是对字符串而言的,指的是字符串所包含的字符个数. public class LengthDemo { public static voi ...

  10. py-day1-6 python 5个灰魔法 【len,index索引,for循环,切片】

    # 索引,下标,获取字符串中的某一个字符. test = 'MuMingJun' v = test[3] print(v) i # 切片 test = 'MuMingJun' v = test[0:- ...