簡析Windows訊息機制

1treeS發表於2019-05-14

Windows訊息機制

視窗程式特徵
一個Windows上的視窗程式,包含外層的視窗,客戶區,選單欄,標題欄以及按鈕,編輯框等!而視窗,控制元件以及音訊,視訊,圖片等檔案統稱為資原始檔(Resource.h),每個資原始檔都對應一個控制程式碼,通過控制程式碼我們可以操控該資原始檔

訊息機制
Windows視窗程式的執行全靠訊息驅動,那什麼是訊息呢?

訊息,從字面理解就是要傳遞給對方的某個東西, 在Windows上我們的任何行為比如單擊滑鼠,雙擊滑鼠,輸入文字都會產生一條對應的訊息

注意:訊息也稱為事件

誰會最先接收到這個訊息呢?

作業系統

誰會去處理這個訊息呢?

作業系統雖然最先接收到訊息,但是它不會立馬處理,它會把這條訊息先放到系統訊息佇列中,再根據控制程式碼等標識將其拷貝到對應的應用程式訊息佇列中。然後該應用程式的訊息迴圈會不斷檢索自己的訊息佇列,並使用回撥函式處理每一條訊息

注意:當應用程式第一次呼叫GDI函式時系統才給程式建立一個應用程式訊息佇列,也稱為執行緒訊息佇列

作業系統是如何知道訊息是由哪一個程式產生的呢?

typedef struct tagMSG{
    HWND hwnd; //接收該訊息的視窗控制程式碼
    UINT message; //訊息常量識別符號,也就是訊息號
    WPARAM wParam; //附加資訊
    LPARAM lParam; //附加資訊
    DWORD time; //當前時間
    POINT pt; //滑鼠座標
}MSG;

就是由上面的 MSG 結構體中的視窗控制程式碼決定的,並且 message 變數標識該訊息的型別,具體如下:

WM_NULL—0x0000 空訊息
0x0001—-0x0087 視窗訊息
0x00A0—-0x00A9 非客戶區訊息
0x0100—-0x0108 鍵盤訊息
0x0111—-0x0126 選單訊息
0x0132—-0x0138 顏色控制訊息
0x0200—-0x020A 滑鼠訊息
0x0211—-0x0213 選單迴圈訊息
0x0220—-0x0230 多文件訊息
0x03E0—-0x03E8 DDE訊息
0x0400—-0x7FFF WM_USER自定義訊息

由於上面這些數值不容易記憶,所以Windows就定義了很多的巨集來標識這些訊息,比如:滑鼠左鍵按下訊息是WM_LBUTTONDOWN,鍵盤按下訊息是WM_KEYDOWN

傳送訊息
傳送訊息的函式有SendMessage,SendMessageCallback,SendNotifyMessage,SendMessageTimeout
寄送訊息的函式主要有PostMessage,PostThreadMessage,PostQuitMessage
廣播訊息的函式有BroadcastSystemMessage,BroadcastSystemMessageEx

傳送和寄送最大的區別就是:傳送的訊息不會被放到應用程式訊息佇列中,寄送的訊息會被放到應用程式訊息佇列中,導致SendMessage必須等訊息處理後才返回,PostMessage將訊息放到訊息佇列後立馬返回

WM_PAINT
WM_PAINT 訊息表示繪製視窗的客戶區,視窗經常會收到這個訊息,第一條 WM_PAINT 通常發生在 WinMain 中呼叫 UpdateWindow 時。WM_PAINT 訊息在哪些情況下會產生呢?

該視窗的某些部分被遮擋
該視窗的大小被調整
客戶區的滾動條滾動

注意:視窗類的 style 欄位為 CS_HREDRAW 和 CS_VREDRAW,才能重繪

WM_PAINT 是個特殊的訊息,它會合並多個 WM_PAINT,目的是方便將多個無效區域合併成一個大的無效區域以及減少重新整理視窗的次數。具體實現:等到應用訊息佇列為空時才傳送WM_PAINT訊息

WM_PAINT 的具體處理流程:

  • BeginPaint 獲取 DC 裝置環境控制程式碼(HDC hdc = BeginPaint(hwnd,&paintstruct))
  • GetClientRect 獲取客戶區矩形區域(GetClientRect(hwnd,&rect))
  • DrawText 重新顯示
  • EndPaint 釋放裝置上下文控制程式碼(EndPaint(hwnd,&paintstruct))

注意:BeginPaint的一個作用就是把Update Region置為空

END

相關文章