GUI自动化测试和做外挂的原理很相似,都是模拟用户的鼠标和键盘操作, 给自己的程序写自动化就是做测试,给别人的程序写自动化就是外挂了。

本文使用的技术也同样适用制作“对对碰”,"找茬" 之类游戏的外挂。

阅读目录

  1. QQ连连看外挂实现原理
  2. GUI自动化测试的原理
  3. 什么是句柄
  4. P/Invoke机制
  5. 获取游戏窗体的句柄
  6. 分析游戏窗口
  7. 对游戏窗口进行截图
  8. 根据游戏规则来写算法
  9. 模拟鼠标点击
  10. 源代码下载

QQ连连看外挂实现原理

1. 先调用Win32 API获取"连连看"游戏窗口的句柄,

2. 根据游戏窗口的句柄,然后获取游戏方块中的像素。

3. 用一个二维数组来保存每个方块的像素

4. 用算法判定两个一样的方块能否"消", 如果能"消"的话,就模拟鼠标去点击这两个方块。 继续"消" 下一组方块。

GUI自动化测试的原理

当你点击窗体中的一个button, button会响应然后执行一些操作。 这个过程的本质是: 你在屏幕上点击一个Button,  Windows系统根据你点击的位置,知道你要点击哪个Button,然后给这个Button发送鼠标点击的消息。

自动化的原理是:  找到控件的句柄,通过句柄给这个控件发送消息,比如“键盘输入”消息或者“鼠标点击”消息。

什么是句柄

所有的Windows控件本质上都是一个窗体(Window). 每个控件/窗体都有一个与之关联的句柄(handle), 可以通过这个句柄来访问,操纵和检测这个控件/窗体

窗体句柄是由系统产生的一个值,你可以把它想象成与窗体关联的一个ID,通过这个ID可以访问相应的窗体。

在.NET中, 句柄的类型是System.IntPtr,  有点类似Int型。

P/Invoke机制

P/invoke机制叫做"平台调用"机制, 因为Win32API 函数是Windows操作系统的一部分,所以它是用传统的C++程序写的,而不是用C#托管代码写的。 所以我们需要一种机制,让C#中可以调用Win32 API函数.

具体的解决方案是: 先为想要使用的Win32函数创建一个C#外覆函数,或者叫别名函数, 然后调用这个别名函数

实例:

在Win32 API中获取窗体的句柄的函数是 FindWindow(),  它的函数签名用C++描述是这样的

HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);

在C#中,给这个Win32 函数创建别名函数

需要先引用命名空间:  using System.Runtime.InteropServices;

[DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

DllImport: 指定要使用的函数所在的DLL文件。

EntryPoint: Win32 API函数的名称.

CharSet.Auto: 让.NET框架来决定如何进行字符类型转换

当为一个Win32函数编写相应的C#方法别名的时候, 几乎总要使用static 和extern, 因为大多数Win32函数都是静态函数,而非实例函数。

注意:别名函数和Win32函数的名称并不要求一致。 但是名称一致可以保证代码的可读性.

获取游戏窗体的句柄

我们用Win32 API 函数来获取“连连看"游戏窗体的句柄

我们现在调用上节介绍的C#中的别名函数FindWindow(),就相当于调用了Win32 API 的FindWindow()函数

FindWindow函数接收2个参数,className 或者WindowName  然后返回句柄.

Spy++是.NET中自带工具,我们可以使用它来获取窗体的名字。

具体用法是,启动spy++, 点击"Findow Window"图标,弹出Findow Window 程序后, 用鼠标拖动“靶心”到你要测试的窗体上。

如下图。 可以得到游戏窗体的名字叫"QQ游戏 - 连连看角色版"

这样我们就能轻松获取 游戏窗体的句柄

IntPtr wndPane = Win32API.FindWindow(null, "QQ游戏 - 连连看角色版");

分析游戏窗口

通过屏幕标尺工具, 我们去测量游戏窗口。 (这个比较繁琐,需要你多次去测量,多次调整后才能得到准确的数据).

可以发现 "游戏区域"  距离游戏窗口 水平方向:15像素, 垂直方向:182像素

游戏中垂直方向有11个方块, 水平方向有19个方块

每个方块 长:31像素, 宽:35像素  如下图

对游戏窗口中的所有方块进行截图

一个方块有31*35=1085个像素,   事实上我们不需要获取方块中所有的像素点。 为了节省性能,我只需要获取一个方块中的几个像素就可以了。

我们需要用到2个函数来实现获取方块的像素。

[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd); [DllImport("Gdi32.dll")]
public static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

GetDC函数的作用是指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄, 它的输入参数是窗口的句柄,  (上节中我们介绍过可以使用FindWindow函数来获取窗口的句柄).  返回的是DC句柄。  (注意这两个句柄是不同的)

GetPixel根据GetDC获取的DC句柄和X坐标,Y坐标来获取像素点。

实例: 我们获取游戏中 "第三排第四列" 的方块的像素, 代码如下:

IntPtr wndPane = Win32API.FindWindow(null, "QQ游戏 - 连连看角色版");
IntPtr hdc = Win32API.GetDC(wndPane);
// X轴方向的像素要这么算15+31*3
// 因为游戏区域距离游戏窗口左边15像素,每个方块宽31像素,
// Y轴方向的像素要这么算 182+35*4
// 因为游戏区域距离游戏窗口上方182,每个方块高35像素
uint color = Win32API.GetPixel(hdc, 15+31*3 + offX, 182+35*4 + offY);

根据游戏规则来写算法

我们用一个二维数组来保存游戏中的所有方块

private Block[,] blocks = new Block[11, 19];

Block对象代表一个方块,如果方块为空,那么Block包含的是背景色。 如果有方块,那么Block对象中保存该方块的9个像素点。

详细请参考代码中的Block对象。

然后分析游戏规则来写算法来遍历二维数组。

垂直方向,如果两个一样的方块,处于同样的Y轴上,中间没有任何方块可以消,  如图

水平方向,如果两个一样的方块,处于同样的X轴上,中间没有任何方块, 可以消,  如图

拐1个弯,  如果两个一样的方块, 其中一个的X轴和另一个Y成90度,并且中间没有任何方块, 可以消,  如图

拐2个弯,  如图

根据上面这些游戏规则,来设计算法, 具体算法请参考源代码

 
 

模拟鼠标点击

模拟鼠标点击的的方法有很多,
其中的一个win32 API 方法为

        [DllImport("user32.dll")]
public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
const int MOUSEEVENTF_MOVE = 0x0001; //移动鼠标
public const int MOUSEEVENTF_LEFTDOWN = 0x0002; //模拟鼠标左键按下
public const int MOUSEEVENTF_LEFTUP = 0x0004; //模拟鼠标左键抬起
const int MOUSEEVENTF_RIGHTDOWN = 0x0008; //模拟鼠标右键按下
const int MOUSEEVENTF_RIGHTUP = 0x0010; //模拟鼠标右键抬起
const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模拟鼠标中键按下
const int MOUSEEVENTF_MIDDLEUP = 0x0040; //模拟鼠标中键抬起
const int MOUSEEVENTF_ABSOLUTE = 0x8000; //标示是否采用绝对坐标

源代码下载

请点击这里下载源代码,  请用Visual Studio 2010打开。
 

C#_自动测试2_连连看外挂的更多相关文章

  1. Android蓝牙连接自动测试工具

    蓝牙连接自动测试工具 1.需求产生 开发不按着需求走都是耍流氓且浪费时间.此工具的需求产生是研发人员在开发产品时涉及到蓝牙驱动和安卓蓝牙两个东西.但是呢,蓝牙不太稳定,那么工作来了.就需要研发人员一边 ...

  2. Ruby Rails学习中:关于测试的补充,MiniTest报告程序,Guard自动测试

    一. 关于测试的补充 1.MiniTest报告程序 为了让 Rails 应用的测试适时显示红色和绿色,我建议你在测试辅助文件中加入以下内容: (1).打开文件:test/test_helper.rb ...

  3. WiFi QC 自动测试:ixChariot API初探

    Chariot虽然给我们提供了友好的界面,但是必须使用命令行或者使用它的API才能 实现自动测试.Chariot在安装的时候会让你选择命令行界面组件,在它的安装目录下面有一些工具, 暂时还不知道是干什 ...

  4. Nightwatch.js – 轻松实现浏览器的自动测试

    Nightwatch.js 是一个易于使用的,基于 Node.js 平台的浏览器自动化测试解决方案.它使用强大的 Selenium WebDriver API 来在 DOM 元素上执行命令和断言. 语 ...

  5. Jenkins+Maven+SVN搭建自动部署、自动测试环境

    .打开http://10.3.15.78:8080/jenkins/,第一次进入里面没有数据,我们需要创建job,我们这有2个项目,需要创建2个job.http://10.3.34.163:9890/ ...

  6. Apache JMeter--网站自动测试与性能测评

    Apache JMeter--网站自动测试与性能测评 2013-02-28 15:48:05 标签:Jmeter From:http://bdql.iteye.com/blog/291987 出于学习 ...

  7. 通过Jasmine和Guard自动测试JavaScript

    原文标题:Autotesting JavaScript with Jasmine and Guard 原文地址:http://edspencer.net/2013/06/15/autotesting- ...

  8. PHP自动测试框架Top 10

    对于很多PHP开发新手来说,测试自己编写的代码是一个非常棘手的问题.如果出现问题,他们将不知道下一步该怎么做.花费很长的时间调试PHP代码是一个非常不明智的选择,最好的方法就是在编写应用程序代码之前就 ...

  9. Qtp自动测试工具

    QTP是基于GUI界面的自动化测试工具,用于系统的功能测试. QTP录制的是鼠标和键盘的消息.QTP录制回放时基于windows操作系统的消息机制.QTP在录制时监听应用程序的消息,监听到之后把消息放 ...

随机推荐

  1. redo文件四

    v$session_wait 用来查询redo buffer的空间信息 select sid,event,seconds_in_wait,state from v$session_wait where ...

  2. 瞬间从IT屌丝变大神——分工安排

    分工安排主要包含以下内容: 公共组件(包括common.css和common.js)一人维护,各子频道专人负责,每个频道正常情况下由一人负责,要详细写明注释,如多人合作,维护的人员注意添加注释信息,具 ...

  3. 记录一次Android交叉编译ffmpeg排查错误

    Android版本手机直播引擎中,引用了libvlc开源库.项目接过来,发现编译脚本中使用了很多用户名下的绝对路径.项目相关人离职,导致这个脚本实际上已经废掉.而且不知道相关路径下有没有其他文件和第三 ...

  4. mysql注册服务

    http://www.2cto.com/database/201301/185456.html ____________________________________________________ ...

  5. hibernate hbm2ddl auto 不能创建表的问题

    http://fuckgis.blog.sohu.com/148751122.html ________________________________________________________ ...

  6. Could not bind factory to JNDI

    将hibernate.cfg.xml中 <session-factory name="SessionFactory">的name属性去掉即可

  7. Java缓存学习之四:EhCache

    EhCache 关键词:纯Java的进程内缓存框架.Java分布式缓存.缓存数据有两级:内存和磁盘.缓存数据会在虚拟机重启的过程中写入磁盘.是hibernate默认的缓存provider: Ehcac ...

  8. F5 刷新功能

    //1.引入单元 uses ShlObj; //2.执行命令 procedure TForm1.Button1Click(Sender: TObject); begin SHChangeNotify( ...

  9. BestCoder Round #73 (div.2)(hdu 5630)

    Rikka with Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  10. How to organize the Template Files in C++

    Normally you put class definitions in a header file and method definitions in a source file. Code th ...