天天看點

DJYGUI系列文章九:GDD消息系統

作者:DJYOS類腦作業系統

1 GDD消息系統概述

消息系統在整個系統中的關系層次如圖所示:

DJYGUI系列文章九:GDD消息系統

圖 4-1 消息系統在GDD中層次示意圖

每個主視窗均會有一個消息隊列,在調用CreateWindow函數建立主視窗時内部會建立一個該主視窗所屬的消息隊列,消息隊列長度為32。子視窗通過主視窗的消息隊列擷取消息。

2 同步消息與異步消息

消息發送方式分為同步發送與異步發送兩種,系統提供兩個API函數:SendMessage,PostMessage,分别用于兩種不同的消息發送方式,它們的差別如下:

SendMessage:用于同步消息發送,消息直接發送到目标視窗的視窗過程函數中,直到該條消息被視窗過程函數處理完成後,該函數才會傳回。

PostMessage:用于異步消息發送,消息發送到目标視窗所屬的消息隊列中後,不等待處理完成,便立即傳回。

3 消息隊列及消息循環與視窗的關系

因為異步消息不需要立即處理,所有主視窗和桌面視窗,都有自己的消息隊列,用于緩存異步消息。對子視窗發送異步消息時,實際是将消息發送到了它所屬的主視窗消息隊列中。在視窗入口函數中,調用GetMessage函數從主視窗消息隊列中取出一條消息,若成功取出一條消息,則調用DispatchMessage函數派發該消息,所謂派發消息其實就是間接調用主視窗的視窗過程函數處理該消息。在視窗入口函數中擷取消息及派發消息執行個體代碼如下:

while(GetMessage(&msg,hwnd))   //從指定的主視窗消息隊列中取出一條消息
 
    {
 
        DispatchMessage(&msg);  //派發該消息
 
    }           

4 視窗過程函數及消息資料結構

所有的成功發送出來的消息,無論是同步還是異步方式發送,最終都會到達視窗過程函數中,視窗過程函數是一個由使用者指定的回調函數,這裡也是視窗程式的主體部分,使用者在這裡可以對接收到的各類消息進行響應處理,對于某些不需要處理的消息必須調用DefWindowProc函數,将該消息交給系統預設處理。視窗過程函數會傳入目前接收到的消息資料結構。該資料結構如下:

typedef struct  tagMSG
 
{
 
    HWND hwnd;
 
    u32 Code;
 
    u32 Param1;
 
u32 Param2;
 
const void* ExData; 
 
}MSG;           

該結構各成員作用如下:

hwnd: 該條消息所屬的目标視窗句柄,視窗過程函數必然是所屬該視窗;

Code: 消息代碼值;

Param1: 消息參數1,不同消息代碼,該參數意義不同;

Param1: 消息參數2,不同消息代碼,該參數意義不同;

ExData: 消息擴充資料,不同消息代碼,該參數意義不同。

上面已提及視窗過程函數主要功能就是根據不同消息做相應的處理,遇到不需要特别處理的消息交給系統做預設處理,一個典型的視窗過程函數執行個體代碼如下:

static  u32 win_proc(MSG *pMsg)
 
{
 
    HWND hwnd;
 
    HDC hdc;
 
    RECT rc,rc0;
 
    hwnd =pMsg->hwnd;
 
    switch(pMsg->Code)
 
    {
 
        case    MSG_CREATE:
 
                GetClientRect(hwnd,&rc0);
 
                CreateWindow(BUTTON,L"關閉",WS_CHILD|BS_NORMAL|WS_BORDER|WS_VISIBLE,RectW(&rc0)-64,RectH(&rc0)-28,60,24,hwnd,IDB_CLOSE,NULL);
 
                GDD_CreateTimer(hwnd,1,5000,TMR_START);
 
                break;
 
        case    MSG_TIMER:
 
              PostMessage(hwnd,MSG_CLOSE,0,0);
 
                break;
 
        case    MSG_NOTIFY:
 
                {
 
                    u16 event,id;
 
                    event =HI16(pMsg->Param1);
 
                    id =LO16(pMsg->Param1);
 
                    if(event==BTN_UP && id==IDB_CLOSE)
 
                    {
 
                        PostMessage(hwnd,MSG_CLOSE,0,0);
 
                    }
 
                }
 
                break;
 
        case    MSG_PAINT:
 
                {
 
                    hdc =BeginPaint(hwnd);
 
                    GetClientRect(hwnd,&rc0);
 
                    SetFillColor(hdc,RGB(170,160,135));
 
                    FillRect(hdc,&rc0);
 
                    SetTextColor(hdc,RGB(0,0,0));
 
                    TextOut(hdc,2,4,wstr,-1);
 
                    EndPaint(hwnd,hdc);
 
                }
 
                break;
 
        case    MSG_CLOSE:
 
                DestroyWindow(hwnd);
 
                return 1;
 
        case    MSG_DESTROY:
 
                PostQuitMessage(hwnd,0);
 
                return 1;
 
        default:
 
                return  DefWindowProc(pMsg);
 
    }
 
    return  0;
 
}           

5 消息代碼及參數說明

該視窗過程函數包含了對建立視窗消息(MSG_CREATE)、定時器逾時消息(MSG_TIMER)、控件狀态變化告知資訊(MSG_NOTIFY)、繪圖消息(MSG_PAINT)、關閉視窗消息(MSG_CLOSE)及銷毀視窗消息等消息對應的處理方法。除了關閉視窗消息及銷毀視窗消息處理方法相同,其他消息應根據應用程式實際需求編寫。上述執行個體隻是定義了部分消息處理方法,GDD還定義了其他視窗消息類型具體參見gdd.h。應用程式可根據實際需求對各消息類型做相應的處理。

系統為使用者定義了一系列通用消息代碼,以下是這些消息的詳細說明。

MSG_CREATE: 視窗建立消息

參數:

Param1: 由CreateWindow的pdata傳入。

Param2: 忽略。

說明:

該消息在視窗建立時,由CreateWindow函數産生,使用者可以在該消息響應中作一些初始化的工作。

MSG_ERASEBKGND: 視窗背景重繪消息

參數:

Param1: 繪圖上下文句柄。

Param2: 忽略。

說明:

在視窗重繪之前,如果有對視窗背景進行重繪的請求,那麼BeginPaint函數内部将會先以同步方式發送該消息,用于先對視窗進行背景進行重繪;背景重繪請求産生的條件為:調用了InvalidateWindow函數,第二個參數 bErase為TURE;具體參考:InvalidateWindow: 設定視窗為無效狀态

​​​​​​​​​​​​​MSG_NCPAINT: 視窗非客戶區繪制消息

參數:

Param1: 忽略。

Param2: 忽略。

說明:

當視窗非客戶區需要重新繪制時(比如視窗由不可見狀态變為可見狀态或使用者主動發送了MSG_NCPAINT消息),當視窗過程收到該消息時,訓示視窗非客戶區需要重新繪制,如果使用者不需要自己繪制視窗非客戶,可以調用DefWindowProc函數,交由系統預設處理。

MSG_PAINT: 視窗客戶區繪制消息

參數:

Param1: 忽略。

Param2: 忽略。

說明:

當視窗客戶區需要重新繪制時(比如視窗由不可見狀态變為可見狀态或使用者主動發送了MSG_PAINT消息)當視窗過程收到該消息時,訓示視窗客戶區需要重新繪制。

MSG_TIMER: 定時器逾時消息

參數:

Param1: 定時器ID。

Param2: 忽略。

說明:

當一個定時器定時時間到來時,便會發送該消息到定時器所屬的視窗,如果該定時器産生的消息未被視窗處理完成,那麼該定時器将不會再重複産生MSG_TIMER消息。

MSG_CLOSE: 視窗請求關閉消息

參數:

Param1: 忽略。

Param2: 忽略。

說明:

如果接收該消息,表示視窗請求關閉,使用者在這裡可以按實際情況處理是否要真正關閉視窗,如果使用者需要繼續關閉視窗,則需調用DestroyWindow函數,否則直接傳回。

MSG_DESTROY: 視窗銷毀消息

參數:

Param1: 忽略。

Param2: 忽略。

說明:

當使用者調用了DestroyWindow函數時,會産生該消息,表示視窗需要被銷毀,使用者可以在這裡做一些資源善後工作,然後必需調用PostQuitMessage函數來訓示視窗需要退出消息循環。

MSG_NOTIFY: 控件通知消息

參數:

Param1: 低16位:控件ID;高16位:控件通知碼。

Param2: 控件視窗句柄。

說明:

該消息由控件向所屬的父視窗發送的消息,用于通知父視窗,控件本身發生了狀态變化,通知碼用于描述控件狀态及其變化等,例如:

控件名稱

控件碼

描述

BUTTON

BTN_DOWN

按鈕被按下

BTN_UP

按鈕彈起

CHECKBOX

CBN_SELECTED

複選框為選中狀态

CBN_UNSELECTED

複選框為未選中狀态

LISTBOX

LBN_SELCHANGE

清單框目前選擇項被改變

MSG_LBUTTON_DOWN: 客戶區滑鼠左鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區按下左鍵時,該視窗會自動收到該消息,如果是觸摸屏裝置的筆針點選螢幕的動作,也會産生該消息。

MSG_LBUTTON_UP: 客戶區滑鼠左鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區松開左鍵時,該視窗會自動收到該消息,如果是觸摸屏裝置的筆針擡起的動作,也會産生該消息。

MSG_SETFOCUS: 視窗獲得焦點

參數:

Param1: 忽略。

Param2: 忽略。

說明:

當調用SetFocusWindow函數時,新設定的焦點視窗,将會收到MSG_SETFOCUS消息,當視窗收到該消息時,說明該視窗已經被設定為目前焦點視窗。對于鍵盤産生的消息,将會自動發送到目前焦點視窗。

​​​​​​​MSG_KILLFOCUS: 視窗失去焦點

參數:

Param1: 忽略。

Param2: 忽略。

說明:

當調用SetFocusWindow函數時,目前舊的焦點視窗,将會收到MSG_KILLFOCUS消息,當視窗收到該消息時,說明該視窗失去焦點。當一個視窗失去焦點後,它将不能接收到鍵盤産生的消息。

​​​​​​​MSG_RBUTTON_DOWN: 客戶區滑鼠右鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區按下右鍵時,該視窗會自動收到該消息。

MSG_LBUTTON_UP: 客戶區滑鼠右鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區松開右鍵時,該視窗會自動收到該消息。

MSG_MBUTTON_DOWN: 客戶區滑鼠中鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區按下中鍵時,該視窗會自動收到該消息。

MSG_MBUTTON_UP: 客戶區滑鼠中鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區松開中鍵時,該視窗會自動收到該消息。

​​​​​​​MSG_MOUSE_MOVE: 客戶區滑鼠移動消息

參數:

Param1: 滑鼠按鍵狀态。可能是以下值組合:

MK_LBUTTON: 滑鼠左鍵為按下狀态。

MK_MBUTTON: 滑鼠中鍵為按下狀态。

MK_RBUTTON: 滑鼠右鍵為按下狀态。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客戶區坐标表示。

說明:

當滑鼠在視窗的客戶區移動時,該視窗會自動收到該消息。

MSG_NCLBUTTON_DOWN: 非客戶區滑鼠左鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區按下左鍵時,該視窗會自動收到該消息,如果是觸摸屏裝置的筆針點選螢幕的動作,也會産生該消息。

MSG_NCLBUTTON_UP: 非客戶區滑鼠左鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區松開左鍵時,該視窗會自動收到該消息,如果是觸摸屏裝置的筆針擡起的動作,也會産生該消息。

MSG_NCRBUTTON_DOWN: 非客戶區滑鼠右鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區按下右鍵時,該視窗會自動收到該消息。

MSG_NCRBUTTON_UP: 非客戶區滑鼠右鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區松開右鍵時,該視窗會自動收到該消息。

MSG_NCMBUTTON_DOWN: 非客戶區滑鼠中鍵點選消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區按下中鍵時,該視窗會自動收到該消息。

MSG_NCMBUTTON_UP: 非客戶區滑鼠中鍵彈起消息

參數:

Param1: 忽略。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區松開中鍵時,該視窗會自動收到該消息。

MSG_NCMOUSE_MOVE: 非客戶區滑鼠移動消息

參數:

Param1: 滑鼠按鍵狀态。可能是以下值組合:

MK_LBUTTON: 滑鼠左鍵為按下狀态。

MK_MBUTTON: 滑鼠中鍵為按下狀态。

MK_RBUTTON: 滑鼠右鍵為按下狀态。

Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用螢幕坐标表示。

說明:

當滑鼠在視窗的非客戶區移動時,該視窗會自動收到該消息。

MSG_KEY_DOWN: 按鍵按下消息

參數:

Param1: 低16位:按鍵值;高16位:保留。

Param2: 該按鍵消息産生的時間,機關為毫秒。

說明:

當鍵盤有按鍵按下時,會産生一次該消息。

​​​​​​​MSG_KEY_UP: 按鍵彈起消息

參數:

Param1: 低16位:按鍵值;高16位:保留。

Param2: 該按鍵消息産生的時間,機關為毫秒。

說明:

當鍵盤有按鍵彈起時,會産生一次該消息。

​​​​​​​PBM_SETDATA:進度條設定資料

參數:

Param1: 進度條資料結構指針。

Param2: 忽略。

說明:

無。

​​​​​​​PBM_GETDATA:進度條獲得資料

參數:

Param1:進度條資料結構指針。

Param2: 忽略。

說明:

無。

​​​​​​​PBM_SETRANGE:進度條設定量程值

參數:

Param1:量程值。

Param2:忽略。

說明:

無。

​​​​​​​PBM_GETRANGE: 進度條獲得量程值

參數:

Param1:忽略。

Param2:忽略。

傳回:

量程值。

說明:

無。

​​​​​​​PBM_SETPOS: 進度條設定目前位置

參數:

Param1:目前位置。

Param2:忽略。

說明:

進度條目前位置值,是相對于量程值。

​​​​​​​PBM_GETPOS: 進度條獲得目前位置

參數:

Param1:忽略。

Param2:忽略。

傳回:

目前位置。

說明:

進度條目前位置值,是相對于量程值。

LBM_ADDSTRING: 清單框增加一個字元項

參數:

Param1:項目索引值。

Param2:字元指針。

傳回:

實際的項目索引值。

​​​​​​​LBM_DELSTRING: 清單框删除一個字元項

參數:

Param1:項目索引值。

Param2:忽略。

傳回:

忽略。

​​​​​​​LBM_SETCURSEL: 清單框設定目前選擇項

參數:

Param1:項目索引值。

Param2:忽略。

傳回:

忽略。

說明:

目前選擇項是指目前被選中的項目。

​​​​​​​LBM_GETCURSEL: 清單框獲得目前選擇項

參數:

Param1:忽略。

Param2:忽略。

傳回:

目前選擇項。

​​​​​​​LBM_SETTOPINDEX: 清單框設定頂部首個可見項

參數:

Param1:項目索引值。

Param2:忽略。

傳回:

忽略。

說明:

清單框顯示時,是叢首個可見項開始,在這前面的項目,是不會顯示出來的。

​​​​​​​LBM_GETTOPINDEX: 清單框獲得頂部首個可見項

參數:

Param1:忽略。

Param2:忽略。

傳回:

頂部首個可見項索引值。

說明:

清單框顯示時,是叢首個可見項開始,在這前面的項目,是不會顯示出來的。

​​​​​​​LBM_GETCOUNT: 清單框獲得目前項目數量

參數:

Param1:忽略。

Param2:忽略。

傳回:

目前項目數量值。

​​​​​​​LBM_RESETCONTENT:清單框的删除所有項目

參數:

Param1:忽略。

Param2:忽略。

傳回:

忽略。

​​​​​​​LBM_GETTEXTLEN:清單框獲得指定項目的字元位元組長度

參數:

Param1:項目索引。

Param2:忽略。

傳回:

指定項目的字元位元組長度。

​​​​​​​LBM_GETTEXT:清單框獲得指定項目的字元内容

參數:

Param1:項目索引。

Param2:輸出的字元内容緩沖區。

傳回:

忽略。

​​​​​​​LBM_SETITEMHEIGHT:清單框設定指定項目的高度

參數:

Param1:項目索引。

Param2:高度值(像素機關)。

傳回:

忽略。

​​​​​​​LBM_GETITEMHEIGHT:清單框獲得指定項目的高度

參數:

Param1:項目索引。

Param2:忽略。

傳回:

指定項目的高度值(像素機關)。

​​​​​​​LBM_SETITEMDATA:清單框設定指定項目的資料值

參數:

Param1:項目索引。

Param2:資料值;這個資料值并不會清單框内部使用,作為使用者自定義使用。

傳回:

忽略。

​​​​​​​LBM_GETITEMDATA:清單框獲得指定項目的資料值

參數:

Param1:項目索引。

Param2:忽略。

傳回:

指定項目的資料值。

6 API說明

6.1 DispatchMessage: 派發消息

u32 DispatchMessage(MSG *pMsg);

頭檔案:

gdd.h

參數:

pMsg: 需要派發的消息。

傳回值:

消息處理結果。

說明:

該函數隻在主視窗消息循環中使用。

6.2 SendMessage: 以同步方式發送消息

u32 SendMessage(HWND hwnd,u32 msg,u32 param1,u32 param2);

頭檔案::

gdd.h

參數:

hwnd: 消息發送的目的視窗句柄。

msg: 消息代碼。

param1: 消息參數1,不同消息,該參數意義不同。

param2: 消息參數2,不同消息,該參數意義不同。

說明:

該函數以同步方式發送消息,支援跨線程發送消息到指定視窗,直到該消息被視窗處理完成後,該函數才會傳回。

6.3 PostMessage: 以異步方式發送消息

BOOL PostMessage(HWND hwnd,u32 msg,u32 param1,u32 param2);

頭檔案::

gdd.h

參數:

hwnd: 消息發送的目的視窗句柄。

msg: 消息代碼。

param1: 消息參數1,不同消息,該參數意義不同。

param2: 消息參數2,不同消息,該參數意義不同。

傳回值:

TRUE: 成功; FALSE: 失敗。

說明:

該函數以異步該方式發送消息,支援跨線程發送消息到指定視窗,用該函數發送一條消息後,便立即傳回,不會等待視窗是否處理完成。

6.4 PostQuitMessage: 異步方式發送退出消息

BOOL PostQuitMessage(HWND hwnd,u32 exit_code);

頭檔案:

gdd.h

參數:

hwnd: 視窗句柄。

exit_code: 使用者自定義的視窗退出碼。

傳回值:

TRUE: 成功; FALSE: 失敗。

說明:

該函數會産生一條MSG_QUIT消息,當主視窗消息循環接收到MSG_QUIT消息時,便會自動銷毀主視窗,并退出消息循環,這意味着一個主視窗過程的結束。 該函數隻在主視窗過程函數的MSG_DESTROY消息中使用,在其它地方使用,将可能産生不可預知的後果;詳細内容可參考視窗的關閉、銷毀、退出過程

6.5 PeekMessage: 以非阻塞方式擷取一條消息

BOOL PeekMessage(MSG *pMsg, HWND hwnd);

頭檔案:

gdd.h

參數:

pMsg: 存放一條所獲得的消息緩沖區。

hwnd: 主視窗句柄。

傳回值:

TRUE: 成功獲得了一條消息; FALSE: 沒有獲得消息。

說明:

從消息隊列頭取出一條消息,該消息将會從消息隊列中删除,該函數隻在主視窗入口函數中擷取消息時使用。

6.6 GetMessage: 以阻塞方式擷取一條消息

BOOL GetMessage(MSG *pMsg,HWND hwnd);

頭檔案:

gdd.h

參數:

pMsg: 存放一條所獲得的消息緩沖區。

hwnd: 主視窗句柄。

傳回值:

TRUE: 成功獲得了一條消息; FALSE: 獲得了一條MSG_QUIT消息。

說明:

該函數隻在主視窗消息循環中使用。

繼續閱讀