如上述,本程序分為了接口層和算法層。上述全局變量和常量,基本都屬于接口層的內(nèi)容。下面,來看接口層的具體實現(xiàn)。其工作的第一步,是要捕獲掃雷窗口并取得其信息。這由函數(shù)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); //檢查“掃雷”窗口的內(nèi)容是否全部顯示在屏幕上 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中的數(shù)值,根據(jù)實測數(shù)據(jù)計算AreaWidth和AreaHeight的值。 AreaWidth := (clientRect.Right - LEFT_MARGIN - RIGHT_MARGIN) div CELL_WIDTH; AreaHeight := (clientRect.Bottom - TOP_MARGIN - BOTTOM_MARGIN) div CELL_HEIGHT;
//檢查游戲是否在進行中,原理為判斷“重開始”按鈕的圖標上的 //某一像素是否是指定的值。該經(jīng)驗由實測得到,只有游戲進行中,該像素才為該值。 if TColor(GetPixel(MineDC, AreaWidth*8 + 8, 30)) <> clBlack then Exit;
result := true; end;
=================================================================
理解這個函數(shù)的工作過程,有幾個要點:
WinAPI函數(shù)FindWindow:用來查找當前桌面上的某個窗口。第一個參數(shù)是指定該窗口的“窗口類”的名字,這個稍微高深了一點,只有研究過Windows SDK編程才會理解。當它為nil的時候,使用第二個參數(shù),也就是窗口標題欄的字符串來查找。若找到這樣一個窗口,則返回值為其窗口句柄,否則為0。
WinAPI函數(shù)GetForegroundWindow:無參數(shù),返回桌面上的當前窗口,也就是標題條加亮的窗口的句柄。
WinAPI函數(shù)GetDC:給定一個窗口句柄,返回它的設備上下文句柄。“設備上下文”實際上就是一個“畫布”,在Delphi中,被封裝成了TCanvas類。獲得了某個設備上下文句柄,就可以用一個TCanvas型的對象指向它(這個過程是,把句柄賦給TCanvas對象的Handle屬性),從而實現(xiàn)畫布的各種操作。
WinAPI函數(shù)GetClientRect:給定某個窗口句柄,取得它的客戶區(qū)矩形,這個矩形是一個TRect類型的變量。調(diào)用這個函數(shù),要用一個TRect型的變量來接收結(jié)果,而不是用返回值。這個結(jié)果的Left和Top成員都必定是0,而Right和Bottom成員其實就是窗口客戶區(qū)的寬和高。
TCanvas類的屬性ClipRect:簡單的說,在此處,該TRect型屬性取得的是該畫布實際上被顯示在屏幕上的矩形部分。只有該畫布不被其它窗口遮擋,并且沒有移出桌面邊界的時候,這個矩形才完全等于等于窗口的客戶區(qū)矩形。這用來判斷掃雷窗口是否全部可見。
WinAPI函數(shù)GetPixel:給定一個設備上下文(畫布)句柄和X,Y坐標,取得一個像素的值。這個值是整型的,可以簡單的強制轉(zhuǎn)換為TColor類型。
上述庫函數(shù),具體說明可以參考MSDN和Delphi自身的幫助文檔,可以得到最為權威、詳細、正確的說明。
不得不說一下GetMineWindow函數(shù)的最后幾行,它牽涉到了對“重開始”按鈕的hack。注意一下,可以發(fā)現(xiàn)那個簡單的臉譜總共有5種狀態(tài):平時的笑臉,自身被按下時的笑臉,在雷區(qū)中按下鼠標時的緊張表情,觸雷時的衰臉和勝利時酷酷的表情~——顯然,只有在第一種情況時,掃雷外掛才應該動作,其它四種時則應該停止。我編了一個臨時程序,找到了一個像素位置,它只有在第一種情況下值為clBlack,其它情況都不是。它的坐標為(AreaWidth*8 + 8, 30),橫坐標是個隨方塊列數(shù)而變的變量,很好理解,因為無論窗口有多寬,該按鈕都是水平居中的。 |