WINX的消息分派机制(续2)

原创 2006年11月05日 18:40:00

我们继续Inside WINX's Message Dispatch。现在开始我们进入了最为关键的部分——WINX是怎么进行消息分派的。

从原理上来讲,WINX的消息分派函数(DispatchMessage)其实与上一篇:《WINX的消息分派机制(续)》中的并无多大的不同,只不过更加智能而已。其中最为关键的是,WINX引入了一种技巧,它可以在编译期判断一个函数是否被重载。简单来说,WINX的消息分派伪代码如下:

template <class T>
class WindowMessage
{
 ...

 BOOL DispatchMessage(
   HWND hWnd, UINT message,
   WPARAM wParam , LPARAM lParam, LRESULT
& lResult)
 {
  T
* pThis = static_cast<T*>(this);
  
if (派生类重载了OnPaint && message == WM_PAINT)
    pThis
->OnPaint(hWnd);
  
else if (派生类重载了OnKeyDown && message == WM_KEYDOWN)
    pThis
->OnKeyDown(hWnd, wParam, lParam);
  
else if (...)
    ...
  
else
    
return FALSE;
  
return TRUE;
 }
};

简单看一个实际的例子,这样做的好处就很明了了。设想WindowMessage的派生类只重载了OnPaint,那么WindowMessage类看起来是这样的:

template <class T>
class WindowMessage
{
 ...

 BOOL DispatchMessage(
   HWND hWnd, UINT message,
   WPARAM wParam , LPARAM lParam, LRESULT
& lResult)
 {
  T
* pThis = static_cast<T*>(this);
  
if (true && message == WM_PAINT)
    pThis
->OnPaint(hWnd);
  
else if (false && message == WM_KEYDOWN)
    pThis
->OnKeyDown(hWnd, wParam, lParam);
  
else if (...)
    ...
  
else
    
return FALSE;
  
return TRUE;
 }
};

并最终被编译器优化为:

template <class T>
class WindowMessage
{
 ...

 BOOL DispatchMessage(
   HWND hWnd, UINT message,
   WPARAM wParam , LPARAM lParam, LRESULT
& lResult)
 {
  T
* pThis = static_cast<T*>(this);
  
if (message == WM_PAINT)
    pThis
->OnPaint(hWnd);
  
else
    
return FALSE;
  
return TRUE;
 }
};

特别地,如果WindowMessage派生类没有响应任何消息,则优化后DispatchMessage为一个空函数,如下:

template <class T>
class WindowMessage
{
 ...

 BOOL DispatchMessage(
   HWND hWnd, UINT message,
   WPARAM wParam , LPARAM lParam, LRESULT
& lResult)
 {
  
return FALSE;
 }
};

这就是WINX的消息分派机制为何比MFC、WTL以及其他任何界面库高效(无论是编译后的代码尺寸上,还是执行效率上)的原因。

好了,现在该是解释WINX如何做到这一点——检测派生类是否重载某个函数的时候了。我们假设,基类(名为Base)中有一个成员函数Func(假设有两个参数),现在有另一个成员函数Caller希望根据派生类是否重载Func来做事情。如下:

template <class T>
class Base
{
 RetType Func(ArgType1 arg1, ArgType2 arg2) { ... }
 
void Caller() {
  
if (派生类重载了Func) { ... }
  
else { ... }
 }
};

一个办法是,略微修改一下基类中的Func原型,加上一个无用参数int unused:

 RetType Func(ArgType1 arg1, ArgType2 arg2, int unused = 0);

或者直接改为可变参数:

 RetType Func(ArgType1 arg1, ArgType2 arg2, ...);

当然,派生类重载Func原型还是需要按我们预期的:

 RetType Func(ArgType1 arg1, ArgType2 arg2);

如此,判断“派生类是否重载了Func”就变成了判断函数原型是否为

 RetType Func(ArgType1 arg1, ArgType2 arg2);

而这正是编译器的拿手好戏。

最后提醒一下,阅读WINX源代码时,你可以发现这个技巧有不少变种(消息分派的实现就与此有细节上的不同),但是其中的道理是完全一致的。

下一篇:WINX的消息分派机制(终结篇)

 

补充:

详细代码请参考WINX库。你也可以通过以下链接在线查看:

WINX的消息分派机制源代码

 

MFC消息映射机制的理解

何谓消息、消息处理函数、消息映射? 消息简单的说就是指通过输入设备向程序发出指令要执行某个操作。具体的某个操作是你的一系列代码。称为消息处理函数。 在SDK中消息其实非常容易理解,当窗口建立后便会...
  • chenjie863
  • chenjie863
  • 2013年12月22日 11:43
  • 1251

Unity3D事件派发机制之Delegate

上一章:【基于MONO事件派发机制之SendMessage】 废话不多说,直接上代码。 [mw_shl_code=csharp,true]/* * NotificationDelegCenter ...
  • dashuaifenyun1991
  • dashuaifenyun1991
  • 2015年01月27日 19:23
  • 1677

轻松搞定RabbitMQ(二)——工作队列之消息分发机制

上一篇博文中简单介绍了一下RabbitMQ的基础知识,并写了一个经典语言入门程序——HelloWorld。本篇博文中我们将会创建一个工作队列用来在工作者(consumer)间分发耗时任务。同样是翻译的...
  • xiaoxian8023
  • xiaoxian8023
  • 2015年09月24日 18:46
  • 10160

J2EE的异步消息机制

  • 2011年07月27日 10:52
  • 43KB
  • 下载

第四课 MFC消息映射机制的剖析 讲述如何运用ClassWizard 2.rar

  • 2009年09月10日 22:08
  • 11.3MB
  • 下载

cocos2d-x层级窗口消息机制Demo

  • 2013年08月06日 11:06
  • 1.92MB
  • 下载

WinSDK编程(续)_windows消息机制

  • 2007年11月03日 22:44
  • 17KB
  • 下载

Windows Server R2 2012安装mysql-5.7.13-winx64

0、下载 MySQL Community Server 打开链接:http://dev.mysql.com/downloads/mysql/ 向下拉页面选择Windows (x86, 64-...
  • kingyumao
  • kingyumao
  • 2017年07月07日 09:43
  • 1661

cocos2d-x游戏开发系列教程-超级玛丽08-消息机制

在超级玛丽游戏里,地图类CMGameMap负责所有的程序逻辑,它包含了背景地图,包含了游戏元素精灵,当游戏中的精灵之间发生碰撞时,比如马里奥撞上砖头这种事情发生时,马里奥对象本身不知道怎么处理这个逻辑...
  • yincheng01
  • yincheng01
  • 2014年02月13日 15:23
  • 2772

cocos2d-x 建立自己的层级窗口消息机制

在开发一些窗口层次比复杂的cocos2d项目时,会发现一些由于没有窗口层次而引起的bug。这些bug让一些从windows平台过来的人觉得很无奈。比如,我们有一个列表控件,我们在其中放了一些菜单,当我...
  • xujiezhige
  • xujiezhige
  • 2012年12月25日 20:57
  • 11329
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WINX的消息分派机制(续2)
举报原因:
原因补充:

(最多只允许输入30个字)