天天看点

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消息。

说明:

该函数只在主窗口消息循环中使用。

继续阅读