今日第一次看 <<Windows核心編程>>第26章, 關於視窗訊息的內容.
收穫甚大, 解決了以往的很多煩惱.
1: 如果有很多個WM_TIMER訊息. 如果WM_TIMER訊息沒有來得及處理, 那麼其將被合并為一個訊息.
2: WM_PAINT同理. WM_TIMER訊息是優先順序最低的訊息.
別的線程給自己線程中的視窗發的訊息,是優先順序最高的訊息.
線程給自己建立的視窗發送的訊息,是次優先順序的訊息.
其次是鍵盤/滑鼠輸入訊息.
再其次是 WM_PAINT和WM_TIMER訊息.
別的認識:
一個視窗對應一個視窗訊息處理函數(也可能多個視窗,對應一個視窗處理函數,看你建立視窗時怎麼指定了)
一個線程對應著一個訊息佇列.
( 這個訊息佇列又分為3個子隊列: 登記訊息佇列(自己給自己發送的訊息), 發送訊息佇列(別人發送給子的訊息), 反饋訊息佇列(自己給別人發送的訊息的反饋通知) )
/////////////////////////////////
另外, 一個背景工作執行緒, 如果其調用了PeekMessage() 那麼其就變成了 UI線程!!!
只不過, 由於這個背景工作執行緒的訊息佇列裡面沒有任何訊息!!!
如果這個背景工作執行緒建立了視窗, 那麼其訊息佇列裡面自然就有了windows給這個視窗投遞的訊息.
記住下面的定理:
1: 若且唯若 一個線程裡面調用了PeekMessage/GetMessage, DispatchMessage()等幾個訊息分配函數, 一個線程才是使用介面執行緒. 但是預設線程的訊息佇列裡面是沒有訊息的.
2: 當線程內部建立了一個視窗之後, 或者, 別的線程往這個線程投遞了訊息了, 線程的訊息佇列裡面才有訊息可取.
/////////////
解惑1:
不難理解為何, TXDATA()由背景工作執行緒搖身一變, 變成了UI線程. 這是因為,
1:cvNameWindow()內部建立了視窗,
2:cvWaitKey()內部調用了訊息指派.
導致這個背景工作執行緒擁有了訊息迴圈, 也擁有了訊息.
解惑2:
當向一個僅有訊息指派沒有視窗的線程投遞訊息時, 這個訊息由那個視窗的訊息處理函數處理???
答案是: 不由哪個視窗的處理函數處理, 而是在GetMessage時, 就可以處理, 也就是, 線上程裡面直接處理, 當然, 你仍然可以把該視窗控制代碼為NULL的訊息進一步 Dispatch, 然後, 如果該線程有視窗, 所有的視窗的視窗處理函數還想都能夠處理該訊息. 呼呼
解惑3:
SendMessage(HWND), 的第一個參數是視窗控制代碼, 那麼訊息怎麼進入線程的訊息佇列裡了呢?
windows內部會檢查, 這個hwnd這個視窗是有誰建立的, 然後把訊息放入對應線程的訊息佇列裡.
假如SendMessage的訊息發送方, 和訊息接收方, 屬於不同的兩個線程, 那麼由於SendMessage是同步的, windows會進行線程的環境切換, 也就是, 發送方的線程將失去CPU資源, 直到訊息被處理返回.
為了防止接收方線程掛掉, 導致發送方線程也跟著掛掉, windows提供了 SendMessageTimeout()API, 可以指定等待的時間.