消息系统在整个系统中的关系层次如图所示:
每个主窗口均会有一个消息队列,在调用CreateWindow函数创建主窗口时内部会创建一个该主窗口所属的消息队列,消息队列长度为32。子窗口通过主窗口的消息队列获取消息。
消息发送方式分为同步发送与异步发送两种,系统提供两个API函数:SendMessage,PostMessage,分别用于两种不同的消息发送方式,它们的区别如下:
SendMessage:用于同步消息发送,消息直接发送到目标窗口的窗口过程函数中,直到该条消息被窗口过程函数处理完成后,该函数才会返回。
PostMessage:用于异步消息发送,消息发送到目标窗口所属的消息队列中后,不等待处理完成,便立即返回。
因为异步消息不需要立即处理,所有主窗口和桌面窗口,都有自己的消息队列,用于缓存异步消息。对子窗口发送异步消息时,实际是将消息发送到了它所属的主窗口消息队列中。在窗口入口函数中,调用GetMessage函数从主窗口消息队列中取出一条消息,若成功取出一条消息,则调用DispatchMessage函数派发该消息,所谓派发消息其实就是间接调用主窗口的窗口过程函数处理该消息。在窗口入口函数中获取消息及派发消息实例代码如下:
while(GetMessage(&msg,hwnd)) //从指定的主窗口消息队列中取出一条消息
{
DispatchMessage(&msg); //派发该消息
}
所有的成功发送出来的消息,无论是同步还是异步方式发送,最终都会到达窗口过程函数中,窗口过程函数是一个由用户指定的回调函数,这里也是窗口程序的主体部分,用户在这里可以对接收到的各类消息进行响应处理,对于某些不需要处理的消息必须调用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;
}
该窗口过程函数包含了对创建窗口消息(MSG_CREATE)、定时器超时消息(MSG_TIMER)、控件状态变化告知信息(MSG_NOTIFY)、绘图消息(MSG_PAINT)、关闭窗口消息(MSG_CLOSE)及销毁窗口消息等消息对应的处理方法。除了关闭窗口消息及销毁窗口消息处理方法相同,其他消息应根据应用程序实际需求编写。上述实例只是定义了部分消息处理方法,GDD还定义了其他窗口消息类型具体参见gdd.h。应用程序可根据实际需求对各消息类型做相应的处理。
系统为用户定义了一系列通用消息代码,以下是这些消息的详细说明。
参数:
Param1: 由CreateWindow的pdata传入。
Param2: 忽略。
说明:
该消息在窗口创建时,由CreateWindow函数产生,用户可以在该消息响应中作一些初始化的工作。
参数:
Param1: 绘图上下文句柄。
Param2: 忽略。
说明:
在窗口重绘之前,如果有对窗口背景进行重绘的请求,那么BeginPaint函数内部将会先以同步方式发送该消息,用于先对窗口进行背景进行重绘;背景重绘请求产生的条件为:调用了InvalidateWindow函数,第二个参数 bErase为TURE;具体参考:InvalidateWindow: 设置窗口为无效状态
参数:
Param1: 忽略。
Param2: 忽略。
说明:
当窗口非客户区需要重新绘制时(比如窗口由不可见状态变为可见状态或用户主动发送了MSG_NCPAINT消息),当窗口过程收到该消息时,指示窗口非客户区需要重新绘制,如果用户不需要自己绘制窗口非客户,可以调用DefWindowProc函数,交由系统默认处理。
参数:
Param1: 忽略。
Param2: 忽略。
说明:
当窗口客户区需要重新绘制时(比如窗口由不可见状态变为可见状态或用户主动发送了MSG_PAINT消息)当窗口过程收到该消息时,指示窗口客户区需要重新绘制。
参数:
Param1: 定时器ID。
Param2: 忽略。
说明:
当一个定时器定时时间到来时,便会发送该消息到定时器所属的窗口,如果该定时器产生的消息未被窗口处理完成,那么该定时器将不会再重复产生MSG_TIMER消息。
参数:
Param1: 忽略。
Param2: 忽略。
说明:
如果接收该消息,表示窗口请求关闭,用户在这里可以按实际情况处理是否要真正关闭窗口,如果用户需要继续关闭窗口,则需调用DestroyWindow函数,否则直接返回。
参数:
Param1: 忽略。
Param2: 忽略。
说明:
当用户调用了DestroyWindow函数时,会产生该消息,表示窗口需要被销毁,用户可以在这里做一些资源善后工作,然后必需调用PostQuitMessage函数来指示窗口需要退出消息循环。
参数:
Param1: 低16位:控件ID;高16位:控件通知码。
Param2: 控件窗口句柄。
说明:
该消息由控件向所属的父窗口发送的消息,用于通知父窗口,控件本身发生了状态变化,通知码用于描述控件状态及其变化等,例如:
控件名称
控件码
描述
BUTTON
BTN_DOWN
按钮被按下
BTN_UP
按钮弹起
CHECKBOX
CBN_SELECTED
复选框为选中状态
CBN_UNSELECTED
复选框为未选中状态
LISTBOX
LBN_SELCHANGE
列表框当前选择项被改变
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区按下左键时,该窗口会自动收到该消息,如果是触摸屏设备的笔针点击屏幕的动作,也会产生该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区松开左键时,该窗口会自动收到该消息,如果是触摸屏设备的笔针抬起的动作,也会产生该消息。
参数:
Param1: 忽略。
Param2: 忽略。
说明:
当调用SetFocusWindow函数时,新设置的焦点窗口,将会收到MSG_SETFOCUS消息,当窗口收到该消息时,说明该窗口已经被设置为当前焦点窗口。对于键盘产生的消息,将会自动发送到当前焦点窗口。
参数:
Param1: 忽略。
Param2: 忽略。
说明:
当调用SetFocusWindow函数时,当前旧的焦点窗口,将会收到MSG_KILLFOCUS消息,当窗口收到该消息时,说明该窗口失去焦点。当一个窗口失去焦点后,它将不能接收到键盘产生的消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区按下右键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区松开右键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区按下中键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区松开中键时,该窗口会自动收到该消息。
参数:
Param1: 鼠标按键状态。可能是以下值组合:
MK_LBUTTON: 鼠标左键为按下状态。
MK_MBUTTON: 鼠标中键为按下状态。
MK_RBUTTON: 鼠标右键为按下状态。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用客户区坐标表示。
说明:
当鼠标在窗口的客户区移动时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区按下左键时,该窗口会自动收到该消息,如果是触摸屏设备的笔针点击屏幕的动作,也会产生该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区松开左键时,该窗口会自动收到该消息,如果是触摸屏设备的笔针抬起的动作,也会产生该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区按下右键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区松开右键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区按下中键时,该窗口会自动收到该消息。
参数:
Param1: 忽略。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区松开中键时,该窗口会自动收到该消息。
参数:
Param1: 鼠标按键状态。可能是以下值组合:
MK_LBUTTON: 鼠标左键为按下状态。
MK_MBUTTON: 鼠标中键为按下状态。
MK_RBUTTON: 鼠标右键为按下状态。
Param2: 低16位: X坐标值; 高16位:Y坐标值; 使用屏幕坐标表示。
说明:
当鼠标在窗口的非客户区移动时,该窗口会自动收到该消息。
参数:
Param1: 低16位:按键值;高16位:保留。
Param2: 该按键消息产生的时间,单位为毫秒。
说明:
当键盘有按键按下时,会产生一次该消息。
参数:
Param1: 低16位:按键值;高16位:保留。
Param2: 该按键消息产生的时间,单位为毫秒。
说明:
当键盘有按键弹起时,会产生一次该消息。
参数:
Param1: 进度条数据结构指针。
Param2: 忽略。
说明:
无。
参数:
Param1:进度条数据结构指针。
Param2: 忽略。
说明:
无。
参数:
Param1:量程值。
Param2:忽略。
说明:
无。
参数:
Param1:忽略。
Param2:忽略。
返回:
量程值。
说明:
无。
参数:
Param1:当前位置。
Param2:忽略。
说明:
进度条当前位置值,是相对于量程值。
参数:
Param1:忽略。
Param2:忽略。
返回:
当前位置。
说明:
进度条当前位置值,是相对于量程值。
参数:
Param1:项目索引值。
Param2:字符指针。
返回:
实际的项目索引值。
参数:
Param1:项目索引值。
Param2:忽略。
返回:
忽略。
参数:
Param1:项目索引值。
Param2:忽略。
返回:
忽略。
说明:
当前选择项是指当前被选中的项目。
参数:
Param1:忽略。
Param2:忽略。
返回:
当前选择项。
参数:
Param1:项目索引值。
Param2:忽略。
返回:
忽略。
说明:
列表框显示时,是丛首个可见项开始,在这前面的项目,是不会显示出来的。
参数:
Param1:忽略。
Param2:忽略。
返回:
顶部首个可见项索引值。
说明:
列表框显示时,是丛首个可见项开始,在这前面的项目,是不会显示出来的。
参数:
Param1:忽略。
Param2:忽略。
返回:
当前项目数量值。
参数:
Param1:忽略。
Param2:忽略。
返回:
忽略。
参数:
Param1:项目索引。
Param2:忽略。
返回:
指定项目的字符字节长度。
参数:
Param1:项目索引。
Param2:输出的字符内容缓冲区。
返回:
忽略。
参数:
Param1:项目索引。
Param2:高度值(像素单位)。
返回:
忽略。
参数:
Param1:项目索引。
Param2:忽略。
返回:
指定项目的高度值(像素单位)。
参数:
Param1:项目索引。
Param2:数据值;这个数据值并不会列表框内部使用,作为用户自定义使用。
返回:
忽略。
参数:
Param1:项目索引。
Param2:忽略。
返回:
指定项目的数据值。
u32 DispatchMessage(MSG *pMsg);
头文件:
gdd.h
参数:
pMsg: 需要派发的消息。
返回值:
消息处理结果。
说明:
该函数只在主窗口消息循环中使用。
u32 SendMessage(HWND hwnd,u32 msg,u32 param1,u32 param2);
头文件::
gdd.h
参数:
hwnd: 消息发送的目的窗口句柄。
msg: 消息代码。
param1: 消息参数1,不同消息,该参数意义不同。
param2: 消息参数2,不同消息,该参数意义不同。
说明:
该函数以同步方式发送消息,支持跨线程发送消息到指定窗口,直到该消息被窗口处理完成后,该函数才会返回。
BOOL PostMessage(HWND hwnd,u32 msg,u32 param1,u32 param2);
头文件::
gdd.h
参数:
hwnd: 消息发送的目的窗口句柄。
msg: 消息代码。
param1: 消息参数1,不同消息,该参数意义不同。
param2: 消息参数2,不同消息,该参数意义不同。
返回值:
TRUE: 成功; FALSE: 失败。
说明:
该函数以异步该方式发送消息,支持跨线程发送消息到指定窗口,用该函数发送一条消息后,便立即返回,不会等待窗口是否处理完成。
BOOL PostQuitMessage(HWND hwnd,u32 exit_code);
头文件:
gdd.h
参数:
hwnd: 窗口句柄。
exit_code: 用户自定义的窗口退出码。
返回值:
TRUE: 成功; FALSE: 失败。
说明:
该函数会产生一条MSG_QUIT消息,当主窗口消息循环接收到MSG_QUIT消息时,便会自动销毁主窗口,并退出消息循环,这意味着一个主窗口过程的结束。 该函数只在主窗口过程函数的MSG_DESTROY消息中使用,在其它地方使用,将可能产生不可预知的后果;详细内容可参考窗口的关闭、销毁、退出过程
BOOL PeekMessage(MSG *pMsg, HWND hwnd);
头文件:
gdd.h
参数:
pMsg: 存放一条所获得的消息缓冲区。
hwnd: 主窗口句柄。
返回值:
TRUE: 成功获得了一条消息; FALSE: 没有获得消息。
说明:
从消息队列头取出一条消息,该消息将会从消息队列中删除,该函数只在主窗口入口函数中获取消息时使用。
BOOL GetMessage(MSG *pMsg,HWND hwnd);
头文件:
gdd.h
参数:
pMsg: 存放一条所获得的消息缓冲区。
hwnd: 主窗口句柄。
返回值:
TRUE: 成功获得了一条消息; FALSE: 获得了一条MSG_QUIT消息。
说明:
该函数只在主窗口消息循环中使用。