激烈振动

Visit My MSN Space

导航

Skin技术实现框架(完)

有过去一个周末了,昨天去看跳水比赛,现场的气氛还是不错的。可惜田亮没有来,否则,光看看观众席的fans也是一种享受啊
废话结束,进入正题,今天讲点以前没说清楚的内容。上次提到了消息反射,但没有深入,这个概念是这样的,许多窗口控件会向父窗口发送一些消息,比如WM_COMMAND消息和WM_NOTIFY消息,通知父窗口一些事件。因为是发给父窗口的,所以控件窗口的过程函数不能捕捉到这些消息。但是,经常我们希望在控件窗口对象中处理这些消息,这样使控件类更加独立。为了实现这个目的,MFC和ATL都提供了消息反射的机制,就是让父窗口在收到这类消息的时候,把它们再发还给控件窗口,这就是消息反射。我们要实现Skin插件,也需要在控件窗口类中收到这些消息,但是,我们不能依赖ATL或者MFC的反射,因为我们希望Skin插件可以被不同的宿主程序使用,而不是局限于ATL和MFC。其他程序可能没有消息反射机制,或者使用了不同的消息反射机制。所以,我们实现了自己的消息反射机制。
CReflectHook类就是用来完成消息反射的,其构造函数接受父窗口的句柄作为参数,然后调用SubclassWindow把对象实例链接到窗口上去,这和控件的实现类似。ProcessWindowMessage是个虚函数,它的定义可以追述到ATL窗口类的最底层,CReflectHook::ProcessWindowMessage实现反射功能,把收到的需要反射的消息发送回控件窗口。但也不是简单的原样返回,而是包装成另一个WM_REFLECT消息,以免和其他消息冲突。当反射消息发会给控件窗口时,控件窗口利用下面三个宏解开WM_REFLECT,并得到原来的消息:
LF_REFLECTED_NOTIFY_CODE_HANDLER
LF_REFLECTED_COMMAND_CODE_HANDLER
LF_REFLECTED_MESSAGE_HANDLER
这几个宏的含义不多说了,熟悉WTL的同学很容易找到答案。另外值得一提的时WM_GETREFLECTOR消息,这个自定义消息可以用来向父窗口查询于其相关联的CReflectHook实例,以避免重复安装反射钩子,因为CReflectHook::ProcessWindowMessage为这个消息返回了this指针。CWidgetHook::Install使用了WM_GETREFLECTOR消息。

值得讲的就这么多了吧,最后说一下怎么写CWidgetHook继承类吧(即控件类),这也是直接影响最终效果的。WTL定义了许多通用控件包装类,把这些类作为CWidgetHook的第二个模板参数可以是后续工作大大简化,当然,如果没有对应的包装类,也可以接收默认参数。
因为借助了ATL/WTL的基础架构,控件类的编写和写一个ATL窗口类非常相似,可以使用ATL/WTL消息映射宏,当然,这些宏需要手工输入,而不象MFC一样提供了Wizard。另外,控件类还可以选择的重载CWidgetHook定义的4个初始化和清理函数,参考Skin技术实现框架(五)。附带的例子中提供了一个Mac按钮类的实现,可以参考,这个按钮例子算是比较复杂的,因为Windows窗口类名为“Button”的窗口实际上包括普通按钮、单选钮和复选框,其他的许多控件实现起来比button容易,当然也有一些比较麻烦的。

关于这个skin框架,基本上应该都讲清楚了,不过肯定比较乱,也许以后有时间整理吧。这里使用了很多WTL的东西,可能熟悉的人并不多,而且最终没有得到微软官方支持,所以要说有多少价值,也说不上,只是喜欢的朋友可以玩一下。我现在也不怎么关注C++的东西了,没办法,新技术发展太快,不得不跟上啊。随便写一点以前的积累,和同学们共勉。

posted on 2004-05-24 16:25  vibration  阅读(4395)  评论(4编辑  收藏  举报