1 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消息。
說明:
該函數隻在主視窗消息循環中使用。