[原创] MicroWindows学习笔记之消息管理

 数据结构

1MSG

/*

 * Message structure

 */

typedef struct tagMSG {

    MWLIST             link;                   /* microwin*/

    HWND        hwnd;

    UINT        message;

    WPARAM      wParam;

    LPARAM      lParam;

    DWORD       time;

    POINT       pt;

} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

所在文件:include\Winuser.h

 

2MWLIST

其中MWLIST为一双向链表结构,其定义为

/* dbl linked list data structure*/

typedef struct _mwlist {              /* LIST must be first decl in struct*/

       struct _mwlist *next;            /* next item*/

       struct _mwlist *prev;            /* previous item*/

} MWLIST, *PMWLIST;

所在文件:include\Mwtypes.h

 

3MWLISTHEAD

/* dbl linked list head data structure*/

typedef struct _mwlisthead {

       struct _mwlist *head;           /* first item*/

       struct _mwlist *tail;              /* last item*/

} MWLISTHEAD, *PMWLISTHEAD;

 

全局变量

MWLISTHEAD mwMsgHead;             /* application msg queue*/

它是一个MWLISTHEAD类型的数据,其定义见上,由它组成消息队列

 

消息队列

通过上面的数据结构,我们可以看见,MicroWindows的消息队列是通过链表的形式组织的。

整个消息通过mwMsgHead这个全局变量串联起来,按照先进先出的原则进出消息。其中,mwMsgHead.head是最老的消息,每次取消息都是从head开始取,而mwMsgHead.tail则是最新的消息,每次入消息都放在tail之后。

 

相关方法

所在文件:mwin\Winuser.c

1SendMessage

1)方法原型:

LRESULT WINAPI

SendMessage(HWND hwnd, UINT Msg,WPARAM wParam,LPARAM lParam)

2)说明:

SendMessage是同步发送消息的方法。

思考:

当初在学Windows编程时,总觉得奇怪,为什么对于窗口、控件的操作,要通过WM_XXX消息的形式呢?通过API方法简单明了,非要用消息不是多此一举吗!前段时间与同事讨论MicroWindows时,突然发现这样做是另有目的。

大多数的图形系统,它的控件系统基本上都不支持多线程操作,即如果想操作控件的东西,那你只能在该控件对象所在的图形线程里做,在其他线程里操作都会有意想不到的后果,用户自己承担责任。这个主要是因为控件体系太过于庞大,做多线程保护会使整个工作量大大增加,而对于应用来说,单线程操作也基本上能满足要求。所以,应用在开发时,都需注意这一点。

Windows通过消息来调用控件的方法,就可以有效的避免多线程操作的问题,因为通过消息把所有的操作进行序列化,放在图形线程里去执行,相当于做了COM里套间的功能。

如果想达到同步执行方法的话,可通过SendMessage方法。所以,对于SendMessage,我觉得MicroWindows的实现是有问题的,它只是简单的调用了窗口的回调函数(注册在窗口类上的WndProc),而没有考虑到多线程问题。如果在非图形线程里调用了SendMessage的话,那它有可能会在该线程里调用控件的方法,与图形线程冲突而导致问题。

 

2PostMessage

1)方法原型

BOOL WINAPI

PostMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)

2)说明

PostMessage是异步发送消息的方法。

将参数打包成MSG放入消息队列中。

其中WM_PAINT是特殊处理的,它并没有发消息,而只是在hwnd->gotPaintMsg置位,一来是因为WM_PAINT消息比较多,放在消息队列里不合适,二来通过置标志位达到WM_PAINT消息合并的效果,三来WM_PAINT优先级比较低,可以放在最后一个处理。

PostMessage也通过开关做鼠标Move消息的合并工作。

 

3GetMessage

1)方法原型

BOOL WINAPI

GetMessage(LPMSG lpMsg,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax)

2)说明

从消息队列中取消息,并将该消息从消息队列中摘除。一般,应用的消息循环都是通过这个方法来取得消息的。

里面的实现是通过PeekMessage来做的。返回值决定要不要退出消息循环。

 

4PeekMessage

1)方法原型

BOOL WINAPI

PeekMessage(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,

       UINT wRemoveMsg)

2)说明

用于从消息队列中取消息,要不要将该消息从消息队列中摘除,取决于最后一个参数wRemoveMsg,它的取值范围为:

其实这个函数才是整个MicroWindows消息的源动力,所有的取消息都从这个入口开始,而且底层的硬件消息也从这里读取。

在这里,做了一个简单的消息优先级的处理:

1] 如果消息队列里有消息(mwMsgHead.head非空),则先处理消息队列里的消息;

2] 当消息队列为空时,看所有窗口有没有paint标志,如果有,则发paint消息;

3] 如果窗口没有paint标志,那么调用MwSelect方法取底层消息;

4] 再没有消息,那直接返回FALSE

思考:

PeekMessage取不到任何消息时,它会返回FALSE,而GetMessage是这么实现的

所以,会不会在没有消息时一直死循环呢?

 

5TranslateMessage

1)方法原型

BOOL WINAPI

TranslateMessage(CONST MSG *lpMsg)

2)说明

这个方法是将WM_KEYDOWN转换为WM_CHAR

 

6DispatchMessage

1)方法原型

LONG WINAPI

DispatchMessage(CONST MSG *lpMsg)

2)说明

这个方法是将消息传到窗口的回调函数(窗口类中的WndProc)。

posted on 2010-04-05 19:54  高原  阅读(579)  评论(0)    收藏  举报

导航