1. 程式人生 > >整理OD學習之深入理解訊息迴圈

整理OD學習之深入理解訊息迴圈

今天我們一起深入探討下帶有對話方塊的訊息迴圈。先看下圖:今天我們就來研究這個圖!!


為了方便研究,我就選用看雪例項裡的一個程式。從圖上你可以看出一個主視窗,還有一個訊息框。為了程式介面的簡單,還請暫時把你看到的這個訊息框當成對話方塊。這樣一來你所看到的2個元素分別就是:主視窗和一個對話方塊。
現在我們就來模擬下你按下“OK”按鈕後,系統到底做了些什麼操作。
當你按下此按鈕,系統就是構建一個訊息結構
MSG {“按鈕控制代碼”,“WM_LBUTTONDBLCLK”,引數1,引數2,“此時滑鼠在螢幕中的座標”}
之後把這個訊息結構放到系統訊息列隊。之後系統會看情況把這個訊息放入主視窗的執行緒訊息佇列中。
這個時候我們的主視窗訊息迴圈中的GetMessage函式就會去自己的執行緒訊息佇列裡取訊息,如果沒有取到,那麼這個函式是不會返回的,原執行緒掛起同時發起執行緒的切換。(在此感謝劉飛同學的補充理解),如果取得訊息的話,那麼DispatchMessage函式就會分析這個MSG結構從而獲得這個“按鈕的控制代碼”,那麼DispatchMessage就會呼叫這個按鈕的回撥函式(按鈕回撥函式包含在USER32.dll中)。按鈕的回撥函式會重新構建這個MSG,使其變成:
 MSG{“按鈕父親視窗的控制代碼(TrackMe對話方塊的控制代碼)”,WM_COMMAND,“OK按鈕的資源號”,0}


並且把重新構建好的MSG結構再次放入主視窗訊息佇列中。這個時候GetMessage函式繼續取訊息,而這個時候的訊息裡的內容已經有所變化,DispatchMessage函式分析新來的MSG結構獲得的控制代碼已經是對話方塊視窗的控制代碼,這個時候DispatchMessage函式就會去呼叫對話方塊的訊息回撥函式,令人興奮的是,對話方塊的訊息回撥函式是程式設計師自定義的。這樣一來,按鈕的點選就和過程函式扯上了關係。
當然啦,上面說的還是比較的膚淺,其實裡面還涉及到更多的訊息的轉換,我就不介紹了,有興趣的讀者用OD跟下就會發現其細節。

"

    上面的轉載中,我標紅了兩處比較重要的資訊:控制元件的訊息,和轉發到父視窗的WM_COMMAND訊息。下面,我以windbg除錯calc.exe為例,演示作者的意圖。

    以Button 0為例,它的控制代碼值為0206006


Button 0的控制元件ID:0x0082


Button 0的父視窗資訊:


    它的父視窗看著像是一個組合框,它的控制代碼值為06057E,和SPY++獲得的結果一致。


    要驗證原作者的結論是否正確,只需下在user32!InternalCallWindProc函式(前面的文章說過這是個萬能訊息斷點)處對WM_LBUTTON和WM_COMMAND訊息下條件斷點:

0:004> bp USER32!InternalCallWinProc ".if((dwo(esp+8)==00020606&dwo(esp+c)==201)|(dwo(esp+8)==0006057E&dwo(esp+c)==111)){.echo LB;}.else{gc;}"
執行windbg並在Button 0上按鍵,windbg馬上會中斷在Button 0的user32!InternalCallWindProc函式處,此時列印呼叫堆疊:
0:004> g
LB
esp=0016ee14
USER32!InternalCallWinProc:
7596c494 55              push    ebp
0:000> kb
ChildEBP RetAddr  Args to Child              
0016ee10 7596c5b7 7455b4a9 00020606 00000201 USER32!InternalCallWinProc @註釋 引數2:00020606是spy++給出的Button 0的控制代碼值,引數3:0x201是滑鼠左鍵按下的訊息
0016ee88 7596cbe9 00000000 7455b4a9 00020606 USER32!UserCallWinProcCheckWow+0x14b
0016eee8 7596cc40 7455b4a9 00000000 0016fc68 USER32!DispatchMessageWorker+0x357
再次執行windbg,它會再次中斷在組合框的user32!InternalCallWindProc函式處,此時列印呼叫堆疊:
0:000> g
LB
esp=0016ebc4 
USER32!InternalCallWinProc:
7596c494 55              push    ebp
0:000> kb
ChildEBP RetAddr  Args to Child              
0016ebc0 7596c5b7 75985b91 0006057e 00000111 USER32!InternalCallWinProc @註釋 引數2:0006057e是spy++給出Button 0的父視窗的控制代碼,引數3:111是WM_COMMAND訊息
0016ec38 75964ede 00000000 75985b91 0006057e USER32!UserCallWinProcCheckWow+0x14b
0016ec94 75964f4d 00787e10 00000111 00000082 USER32!DispatchClientMessage+0xcf
...
綜上所述,恰如原作者所述:控制元件上的訊息會被轉換成父視窗的WM_COMMAND訊息。