Win32程式設計API 基礎篇 訊息迴圈

2022-08-16 12:27:10 字數 4239 閱讀 3793

訊息迴圈

理解訊息迴圈

為了編寫任何即使是最簡單的程式,了解windows程式的訊息迴圈和整個訊息傳送結構是非常有必要的。既然我們已經嘗試了一點訊息處理的東西,我們應該對整個程式有更深入的理解,如果你沒有理解訊息是怎麼發生的和它們執行的機制,那接下來的內容你會感到很蛋疼。

什麼是訊息?

一條訊息是乙個整數值,如果你查閱你的標頭檔案(這是個好的查閱api的工作慣例)你會發現像下面的東西:

1

#define wm_initdialog 0x0110

2#define wm_command 0x011134

#define wm_lbuttondown 0x0201

還有很多類似的東西。在windows中訊息幾乎被運用在基本水平上的所有通訊,如果你想要乙個視窗控制(只是乙個制定的視窗)做某些事情你需要傳送給它一條訊息;同樣的如果另乙個視窗想讓你做某些事情,它會傳送給你一條訊息;如果某些像使用者點選鍵盤、移動滑鼠、點選按鈕的事件發生,那麼相應的訊息會被系統傳送到受影響的視窗,如果你是其中乙個受影響的視窗,那麼你需要處理訊息並採取相應的行動。

每條視窗訊息都可能有兩個引數,wparam和lparam,最初wparam是16位而lparam是32位,但是在win32中它們都是32位。不是每條訊息都需要用到這些引數,用到時的用法也不同,舉個例子,wm_close訊息就都沒有用到這兩個引數,這時我們可以忽略這兩個採納數;而wm_command就同時用到了這兩個引數,wparam包含了兩個值,hiword(wparam)是一條通知訊息(如果可用的話),loword(wparam)是乙個傳送訊息的控制或選單id。

lparam是控制傳送訊息或null(如果訊息不是從控制中來的話)的hwnd(視窗控制代碼)

hiword()和loword()被windows巨集定義,這兩個值都是windows中的巨集定義,乙個指32位(0xffff0000)的高16位(ffff),乙個指32位的低16位(0000);在win32中乙個word表示的是16位,而dword(double word)才表示32位

你可以通過postmessage()或sendmessage()這兩種方式傳送訊息。postmessage()將訊息插入到訊息佇列中然後馬上返回,這意味著即使一次postmessage()的呼叫被完成時,訊息可能還沒被處理;sendmessage()直接傳送訊息給視窗並且會不會立即返回,知道視窗完成了對訊息的處理。如果我們想關閉乙個視窗,我們可以通過postmessage(hwnd, wm_close, 0, 0)傳送乙個wm_close的訊息,這跟我們點選視窗右上方的x按鈕有同樣的效果,注意在wm_close訊息的相應處理中,wparam和lparam都是0,這是因為剛才提到的在wm_close訊息處理中沒有用到這兩個引數。

對話方塊

一旦你開始使用對話方塊盒子,為了跟它們交流你將需要傳送訊息給控制。你可以通過使用getdlgitem()通過使用id先獲取控制的控制代碼然後使用sendmessage(),或者你可以使用senddlgitemmessage(),這個方法組合了上面的兩個步驟。你給它乙個視窗控制代碼和孩子id將會得到乙個孩子控制代碼,然後向他傳送訊息。senddlgitemmessage()和類似的apigetdlgitemtext()將會作用在所有的視窗上,而不僅僅是對話方塊。

什麼是訊息佇列?

讓我們試著想象當你忙著處理wm_paint的時候突然使用者用鍵盤輸入一堆東西,會發生什麼事情?你繪圖的時候被鍵盤打斷應該拋棄嗎?當然不是!很明顯不管拋棄哪個都不是正確的做法,所以我們有了訊息佇列。新增post過來的訊息會被新增到訊息佇列中來,當訊息被處理時訊息就會從訊息佇列中被移除,這確保了你不會錯過一條訊息,如果你正在處理一條訊息,那麼其他訊息就會在佇列中等待直到你開始處理它們。

什麼是乙個訊息環?

1

while(getmessage(&msg, null, 0, 0) > 0)2

1、在訊息佇列裡,訊息環呼叫getmessage()方法,如果你的訊息佇列空了,那麼你的程式

將會停止然後等待訊息,相當於掛起的狀態

2、當乙個事件發生時,會導致一條訊息加入到訊息佇列中(比如系統註冊乙個滑鼠點選)

getmessage()返回乙個正值表明有乙個訊息要處理,並且複製給我們傳遞給它的msg數

據結構的成員,方法也可能會返回0如果訊息是wm_quit,如果是發生錯誤的話方法會

返回負數。

3、我們得到訊息(在msg變數中)然後把它傳遞給translatemessage(),這會產生一點額外

的處理,將虛擬的鍵盤點選翻譯成字元訊息,這個步驟實際上是可選的,如果不需要時

它不會發生。

4、一旦上面的步驟完成,我們把訊息傳遞給dispatchmessage(),dispatchmessage()會做的

工作就是拿到訊息,檢查它是哪個視窗的然後找到對應視窗的訊息處理程式,接著呼叫

訊息處理程式,並且將視窗的控制代碼,訊息,wparam和lparam四個引數傳遞給它。

5、在你的訊息處理程式中,你會檢查引數訊息,然後對它做任何你想做的事情,如果你沒

有處理指定的訊息,那麼預設它會呼叫defwindowproc()方法,這個訊息處理的預設操作,

通常意味著什麼都不做。

6、一旦你已經完成了訊息處理,你的訊息處理程式會返回,dispatchmessage()返回,然後

我們又回到了環開始的地方。

這是視窗程式中乙個非常重要的概念,你的訊息處理程式不是神奇地由系統呼叫,實際上你是間接地通過dispatchmessage()呼叫。如果你想要的話,你可以在視窗控制代碼中使用getwindowlong()直接呼叫視窗處理程式。

1

while(getmessage(&msg, null, 0, 0) > 0)2

我試著用前面的**,但是並沒有正常工作,因為有各種各樣的問題比如unicode/ansi編碼翻譯等,呼叫定時器**方法不會占用,這可能會打破我們目前的所有但微不足道的程式,所以你可以嘗試,但在實際的**中不要真的這麼做: )

注意,我們使用getwindowlong()來檢索視窗相關的訊息處理程式,為什麼我們不直接呼叫wndproc()呢?嗯,我們的訊息環是要對我們程式中所有視窗都適用的,包括有自己的視窗過程的按鈕和列表框,所以我們應該保證呼叫了正確的視窗過程,因為多個視窗可以使用同乙個視窗過程,所以第乙個引數(視窗控制代碼)用來告訴視窗過程訊息屬於哪個視窗的。

正如你所看到的,你的應用程式的大多數時間都花費在執行這個訊息迴圈,你可以愉悅地傳送訊息給可以處理它們的快樂的視窗。但是當你想退出程式時你會怎麼做?因為我們使用了乙個while()迴圈,如果getmessage()返回了false,迴圈將會結束並且到達我們winmain()的終點接著退出程式。這正是postquitmessage()完成的東西,它把wm_quit訊息放入佇列中而不是返回乙個正值,getmessage()會填充msg資料結構的內容然後返回0,在這個時候msg的wparam成員就包含了你傳遞給postquitmessage()的值,這裡你可以忽略它,從winmain()的返回值將會使用在程序結束的退出**中。

重點:getmessgae()將會返回-1如果出現錯誤的話,確保記住這個,否則在某些時候會讓你很蛋疼。。。即使getmessage()被定義用來返回乙個布林值,它也能夠返回true或false之外的值,因為bool使用uint(unsigned int)來定義的。下面的**例子可能可以執行,但是不會正確地處理一下條件:

1

while(getmessage(&msg, null, 0, 0))2

3while(getmessage(&msg, null, 0, 0) != 0)4

5while(getmessage(&msg, null, 0, 0) == true)

上面都是錯的!就像我剛剛提到的,它可能跟我第乙個教程裡使用的差不多,只要getmessage()沒有失敗它會工作地很好,即使你的**是正確的,這個也不是正確的,但是在很多情況下這個**是錯誤的不能正常工作,當getmessage()發生失敗的時候!這裡我們鄭重說明和糾正,請原諒我錯過了一些要點。

1

while(getmessage(&msg, null, 0, 0) > 0)

這個才是正確的!

我希望現在你對視窗訊息迴圈有更好的理解,如果還不是非常理解的話,別害怕,一旦你使用它們一段時間之後情況會好很多。

win32程式設計 滑鼠訊息

忙起來的時候感覺什麼都不缺,空下來以後才發現什麼都沒有。網易雲熱評 一 基本滑鼠訊息 wm lbuttondown 滑鼠左鍵按下wm lbuttonup 滑鼠左鍵抬起wm rbuttondown 滑鼠右鍵按下wm rbuttonup 滑鼠右鍵抬起wm mousemove 滑鼠移動訊息1 訊息引數 w...

win32 訊息機制

2 windows訊息系統組成 訊息佇列 作業系統負責為程序維護乙個訊息佇列,程式執行時不斷地從訊息佇列進行訊息的獲取,處理訊息 訊息迴圈 應用程式不斷地獲取訊息,處理訊息構成訊息迴圈。3 win32訊息路由 1.訊息產生 2.系統將訊息排列到其應該排放的執行緒的訊息佇列中。3.執行緒中的訊息迴圈呼...

win32 訊息機制

本次使用的開發環境是vs2013,使用的開發語言是c c 建立的專案是win32專案 當 windows 應用程式開始執行時,系統會為該程式建立乙個訊息 佇列用於存放訊息,然後用 getmessage 等進行訊息獲取處理。程式從佇列中獲取訊息後處理 分為系統訊息佇列 有系統維護,存放系統產生的訊息如...