程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 掃雷外掛的設計與實現(三)

掃雷外掛的設計與實現(三)

編輯:Delphi
 如上述,本程序分為了接口層和算法層。上述全局變量和常量,基本都屬於接口層的內容。下面,來看接口層的具體實現。其工作的第一步,是要捕獲掃雷窗口並取得其信息。這由函數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),橫坐標是個隨方塊列數而變的變量,很好理解,因為無論窗口有多寬,該按鈕都是水平居中的。

  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved