前面講到要做一體化自動化測試框架,那么,最重要的是要解決什么呢?
相信了解Windows編程的人員,都能發現這個問題所在。在窗體中,寫下代碼,控制每一個控件的輸入是非常簡單的事。但是,一旦顯示了一個模態窗體,原有的流程代碼會不再往下執行,而是停留在新窗體中,等待消息相應。這就是我們代碼控制界面的關鍵問題。
這是什么道理呢?
我使用的是Delphi系統,所以我可能使用VCL框架來解釋這個問題。但是其他語言同樣適用。
在Windows程序中,WinMain是入口。而WinMain的處理,就是一個典型的死循環,先從消息隊列中取出消息,然后再給各窗體派發消息。
為了方便理解,我們將這個模型簡化,就是一個死循環A.中間在處理任意的代碼。
現在,由于調用了某一段處理,進入了另外一個死循環B.當代碼從A函數進入了B,那么當然,A循環下面的代碼當然只能停留下來,直到B循環結束。
而在Windows界面中,模態窗體就是一個消息死循環。當Windows彈出一個模態窗體的時候,其消息隊列獨立處理,不再走整個應用程序的消息循環。
現在比較明白了,不能方便控制界面的原因在于Windows應用程序并不是流程化的,而是消息驅動的。
明白了這個道理,就有可能找到突破口。我想到了鉤子。在Delphi中使用鉤子,推薦使用FastCode.既然程序從A循環進入到B循環,我不能繼續執行A循環的代碼,那么,可不可以在進入B循環后,繼續執行A的代碼呢?
這應該是可行的。關鍵在于我必須做到B循環中,能夠調用到我的代碼。
在Delphi的一般窗體,你可以通過使鉤子Hook住TForm的DoShow方法。那樣,窗體不管是否是ShowModal的,都會觸發,然后通過給此窗體發送一個特殊消息,并在此窗體中,使用鉤子,處理此消息。那么就可以在窗體完全顯示之后,真正處理你的任務了。這里有一個技巧,窗體真正顯示,并不是調用DoShow的時候,而是經過Windows的消息循環,完全處理好所有顯示相關消息之后。這里,通過消息循環機制,給它發送一個額外消息,那么可以保障,觸發你的任務的時機,是在窗體處理完原有消息之后。
當然了,在VCL中,并不是這么簡單就能處理所有問題。最主要的是那些標準Windows窗體,比如MessageBox,OpenDialog.這些窗體不是由TForm組合而成的。所以對象和消息機制都不一樣。需要單獨處理。
這里有一種方式,是通過定時器,定時查詢活動窗體狀態。如果檢測到非標準Windows窗體,手動觸發你的任務。也是一種權衡解決方式。
由于代碼版權問題,我這里不能貼出這些代碼,不過主要意思應該都講清楚了吧。
總結以下這個關鍵點:消息機制和流程代碼的沖突,是根本原因簡單的模型,就是循環嵌套循環問題使用鉤子,在循環開始處,觸發任務這樣,基本就可以控制界面了。
原文轉自:http://www.anti-gravitydesign.com