以文本方式查看主题

-  曙海教育集团论坛  (http://sun4.cn/bbs/index.asp)
--  Delphi程序设计  (http://sun4.cn/bbs/list.asp?boardid=76)
----  扫雷外挂的设计与实现(三)  (http://sun4.cn/bbs/dispbbs.asp?boardid=76&id=2562)

--  作者:wangxinxin
--  发布时间:2010-12-14 10:40:17
--  扫雷外挂的设计与实现(三)

如上述,本程序分为了接口层和算法层。上述全局变量和常量,基本都属于接口层的内容。下面,来看接口层的具体实现。其工作的第一步,是要捕获扫雷窗口并取得其信息。这由函数GetMineWindow来完成:

=================================================================

//试图取得可用的扫雷窗口,返回值表示是否成功。若成功,则全局变量
//MineWnd、MineDC、AreaHeight、AreaWidth都得到相应的填充。若失败,则以上变量的值无意义。

function GetMineWindow: Boolean;
var
  clientRect: TRect;
begin
  result := false;

  MineWnd := FindWindow(nil, MINE_WINDOW_TITLE);           //检查是否存在“扫雷”窗口,并且必须为当前窗口
  if (MineWnd = 0) or (GetForegroundWindow <> MineWnd) then
    Exit;

  MineDC := GetDC(MineWnd);                                //取得“扫雷”窗口的设备上下文
  if MineDC = 0 then
    Exit;

  GetClientRect(MineWnd, clientRect);                      //检查“扫雷”窗口的内容是否全部显示在屏幕上
  with TCanvas.Create do
    try
      Handle := MineDC;
      if (ClipRect.Left <> clientRect.Left) or
         (ClipRect.Right <> clientRect.Right) or
         (ClipRect.Top <> clientRect.Top) or
         (ClipRect.Bottom <> clientRect.Bottom) then
        Exit;
    finally
      Free;
    end;

  //从已获得的clientRect中的数值,根据实测数据计算AreaWidth和AreaHeight的值。
  AreaWidth := (clientRect.Right - LEFT_MARGIN - RIGHT_MARGIN) div CELL_WIDTH;
  AreaHeight := (clientRect.Bottom - TOP_MARGIN - BOTTOM_MARGIN) div CELL_HEIGHT;

  //检查游戏是否在进行中,原理为判断“重开始”按钮的图标上的
  //某一像素是否是指定的值。该经验由实测得到,只有游戏进行中,该像素才为该值。
  if TColor(GetPixel(MineDC, AreaWidth*8 + 8, 30)) <> clBlack then
    Exit;

  result := true;
end;

=================================================================

理解这个函数的工作过程,有几个要点:

WinAPI函数FindWindow:用来查找当前桌面上的某个窗口。第一个参数是指定该窗口的“窗口类”的名字,这个稍微高深了一点,只有研究过Windows SDK编程才会理解。当它为nil的时候,使用第二个参数,也就是窗口标题栏的字符串来查找。若找到这样一个窗口,则返回值为其窗口句柄,否则为0。

WinAPI函数GetForegroundWindow:无参数,返回桌面上的当前窗口,也就是标题条加亮的窗口的句柄。

WinAPI函数GetDC:给定一个窗口句柄,返回它的设备上下文句柄。“设备上下文”实际上就是一个“画布”,在Delphi中,被封装成了TCanvas类。获得了某个设备上下文句柄,就可以用一个TCanvas型的对象指向它(这个过程是,把句柄赋给TCanvas对象的Handle属性),从而实现画布的各种操作。

WinAPI函数GetClientRect:给定某个窗口句柄,取得它的客户区矩形,这个矩形是一个TRect类型的变量。调用这个函数,要用一个TRect型的变量来接收结果,而不是用返回值。这个结果的Left和Top成员都必定是0,而Right和Bottom成员其实就是窗口客户区的宽和高。

TCanvas类的属性ClipRect:简单的说,在此处,该TRect型属性取得的是该画布实际上被显示在屏幕上的矩形部分。只有该画布不被其它窗口遮挡,并且没有移出桌面边界的时候,这个矩形才完全等于等于窗口的客户区矩形。这用来判断扫雷窗口是否全部可见。

WinAPI函数GetPixel:给定一个设备上下文(画布)句柄和X,Y坐标,取得一个像素的值。这个值是整型的,可以简单的强制转换为TColor类型。

上述库函数,具体说明可以参考MSDN和Delphi自身的帮助文档,可以得到最为权威、详细、正确的说明。

不得不说一下GetMineWindow函数的最后几行,它牵涉到了对“重开始”按钮的hack。注意一下,可以发现那个简单的脸谱总共有5种状态:平时的笑脸,自身被按下时的笑脸,在雷区中按下鼠标时的紧张表情,触雷时的衰脸和胜利时酷酷的表情~——显然,只有在第一种情况时,扫雷外挂才应该动作,其它四种时则应该停止。我编了一个临时程序,找到了一个像素位置,它只有在第一种情况下值为clBlack,其它情况都不是。它的坐标为(AreaWidth*8 + 8, 30),横坐标是个随方块列数而变的变量,很好理解,因为无论窗口有多宽,该按钮都是水平居中的。

ggyy 2005-10-30 21:27:47

互联网时代的财富神话,想在网上兼职的朋友必看
访问 www.gujunzhan.isme.net    让我们分享成功的喜悦。 联系191461907

大多数人靠打工拿工资,用自己的血汗去成就老板的事业,用自己的辛勤去烘托领导的辉煌。工作40年工资不过千,省吃俭用几十年,买个小套房还要借钱。

做生意好赚钱。十多年前第一批被人认为“没出息”的去摆地摊,十多年后的今天个个成了大老板,今天你也要摆地摊,100年也成不了大老板!生意竞争越来越激烈,办工厂?开百货?炒股票?做期货?

有人说,我有技术就好了。其实送你百项专利也知识废纸一张,有几个教授、工程师是富翁?

有人说,我要是有资金就好了,其实借你一千万你敢拿过去做保证赚钱的生意?

有人长期走入赚钱的误区,一提到钱就想到开工厂、做生意。这一想法不突破就抓不住许多在他看来不可能的新机遇。

真正想一想,成功与失败、富有与贫穷只是因为当初的一念之差。当初要带几千元杀进股市几年后便成了百万富翁。当初只要花几百元愿意去摆地摊10年后就成了大老板。

可是有人说,如果我当初做会比他们赚钱更多。不错,是的,你的能力比他强,你的资金比他多,你的经验或许比他足。可是明摆着就是当初一念之差,你的观念决定了你当初不去做,你不去做的观念决定了你10年后的今天还是很穷,不同的观念导致了不同的人生。

有人面对一个来之不易的良好机会总是拿不定把握,于是去问他人,问了10人肯定9人说不能做,于是放弃了。

其实你不知道机遇来源于新生事物,而新生事物之所以新就是因为90%以上的人还不知道、不认识,等90%的人知道了就不再是新生事物。

就拿网上赚钱来说,你问10个人,很可能10个人都摇头,但再过一段时间,这10个人点头时,你只能做那10个人的下线了。撑死胆大的饿死胆小的,你是哪一类?难道非要全国人民告诉你网络真的可以赚钱你才加入吗?那个时候什么都晚了!