看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧.

1. 先看下CPaintManagerUI类的MessageLoop函数:

  1. void CPaintManagerUI::MessageLoop()
  2. {
  3. MSG msg = { 0 };
  4. while( ::GetMessage(&msg, NULL, 0, 0) ) {    // 获取消息
  5. if( !CPaintManagerUI::TranslateMessage(&msg) ) { // 消息过滤
  6. ::TranslateMessage(&msg);
  7. ::DispatchMessage(&msg); // 分发到窗口的消息处理窗口中. 也就是调用CWindowWnd类的__WndProc函数或是__ControlProc函数.
  8. }
  9. }
  10. }

消息第一次会由CPaintManagerUI类的TranslateMessage消息接收到.

2. 调用CWindowWnd::Create创建窗口.  完成以下操作:

1) 如果要子类下Window的控件(就是系统的控件, 而不是duilib的模拟控件), 就设置__ControlProc函数为消息回调函数.

2)不子类化, 就注册窗口类. 此时设置__WndProc为窗口消息处理回调函数.

3)用CreateWindowEx API函数创建窗口.

这里先不看子类化相关的, 我要先看明白标准的窗口创建过程.  这也操作后消息就会分发到__WndProc了,

3. 看下__WndProc函数的定义:

  1. LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2. {
  3. CWindowWnd* pThis = NULL;
  4. if( uMsg == WM_NCCREATE ) { // 要在此消息中把类于窗口进行绑定
  5. LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);   // 来自于CreateWindowEx函数的最后一个参数( 也就是CWindowWnd对象指针了 )
  6. pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
  7. pThis->m_hWnd = hWnd;
  8. ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); // 设置到窗口的用户数据中
  9. }
  10. else {
  11. pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
  12. if( uMsg == WM_NCDESTROY && pThis != NULL ) {
  13. LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);    // 收到窗口能处理到的最后一个消息了, 要进行收尾工作了.
  14. ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);    // 取消类对象与窗口的绑定关系
  15. if( pThis->m_bSubclassed ) pThis->Unsubclass();
  16. pThis->m_hWnd = NULL;
  17. pThis->OnFinalMessage(hWnd);
  18. return lRes;
  19. }
  20. }
  21. if( pThis != NULL ) {
  22. return pThis->HandleMessage(uMsg, wParam, lParam);  // 在此调用继承类的消息处理函数
  23. }
  24. else {
  25. return ::DefWindowProc(hWnd, uMsg, wParam, lParam); // 未绑定类对象, 就调用默认的窗口消息处理函数
  26. }
  27. }

消息第二次就由__WndProc接收到, 然后再传到CWindowWnd类的HandlerMessage函数中.

3. 看看CWindowWnd类的继承类对于HandlerMessage虚函数的实现.

  1. LRESULT CMainWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2. {
  3. LRESULT lRes        = 0;    // 消息处理返回值.
  4. BOOL    bHandled    = TRUE; // 消息是否要继续往下传.
  5. switch ( uMsg )
  6. {
  7. case WM_CREATE: lRes    = OnInitResource( bHandled ); break;  // 进行初始化工作. 比如最重要的XML加载解析工作.
  8. default:
  9. bHandled    = FALSE;
  10. }
  11. if ( bHandled )
  12. {
  13. return lRes;
  14. }
  15. if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) )    // 传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作
  16. {
  17. return lRes;
  18. }
  19. return CWindowWnd::HandleMessage( uMsg, wParam, lParam );  // 没处理过的就调用CWindowWnd类的默认消息处理函数吧.
  20. }

在这里就是用户要按消息进行具体的处理了. 之后要传到CPaintManagerUI类对象的MessageHandler函数. 未处理的消息就要返回给CWindowWnd类的默认消息处理函数来处理了.

4.  CPaintManagerUI类的TranslateMessage, MessageHandler函数的内容.

  1. BOOL CPaintManagerUI::TranslateMessage(const LPMSG pMsg)
  2. {
  3. HWND hwndParent = ::GetParent(pMsg->hwnd); // 获取消息接收窗口的父窗口
  4. UINT uStyle = GetWindowStyle(pMsg->hwnd); // 获取窗口的样式
  5. LRESULT lRes = 0;
  6. for( int i = 0; i < m_aPreMessages.GetSize(); i++ ) { // 这个m_aPreMessage保存着CPaintManagerUI类对象.
  7. CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);
  8. if( pMsg->hwnd == pT->GetPaintWindow() // 消息是否属于当前CPaintManagerUI绑定的窗口
  9. || (hwndParent == pT->GetPaintWindow() && ((uStyle & WS_CHILD) != 0)) ) // 消息是否为当前窗口中窗口的消息, (如ActiveX控件 )
  10. {
  11. if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return TRUE; // 此时就调用PreMessageHandler过滤函数.
  12. }
  13. }
  14. return FALSE;
  15. }

m_aPreMessage为静态成员变量, 在CPaintManagerUI::Init进行窗口与此类绑定时添加到此变量中.

5. CPaintManagerUI::PreMessageHandler消息过滤函数.

  1. BOOL CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)
  2. {
  3. // 遍历当前的消息过滤列表. m_aPreMessageFilter的元素为IMessageFilterUI接口.只一个虚函数MessageHandler.
  4. // 用户可以添加此接口的继承类变量到m_aPreMessageFilters列表中. ( 调用AddMessageFilter函数实现 )
  5. for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ )
  6. {
  7. BOOL bHandled = FALSE;
  8. LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
  9. if( bHandled ) {
  10. return TRUE;
  11. }
  12. }
  13. // 以下是对几个按键消息的过滤.
  14. // WM_KEYDOWN     检查是否为VK_TAB键, 要进行控件焦点的移动.
  15. // WM_SYSCHAR     获取与wParam中的字符加速键匹配的控件, 并激活它.
  16. // WM_SYSKEYDOWN  生成控件事件( 用TEventUI来模拟 )
  17. }

5. CPaintManagerUI::MessageHandler函数.

1) 遍历m_aMessageFilters列表中的IMessageFilterUI接口, 并调用MessageHandler函数, 再次进行相关的消息过滤功能.(与上面的m_aPreMessageFilters类似)

2) 在此会处理窗口的WM_PAINT消息. 显示所有控件的外观与状态.

3) 处理鼠标事件, 实现控件激活和相关事件.

4) 处理WM_TIMER消息, 所有控件要用CPaintManagerUI的SetTimer, KillTimer等函数实现计时器功能.

5) 处理CPaintManagerUI类的自定消息, WM_APP + 1与 +2,

WM_APP + 1是用于控件延迟销毁控件对象

WM_APP + 2销毁异步消息的处理.

( 异步控件消息用CPaintManagerUI::SendNotify函数, 把消息对象添加到m_aAsyncNotify列表中, 再PostMessage函数WM_APP + 2 )

5) 其它基本的窗口相关消息的处理.

CPaintManagerUI把DUILIB内部的事件都是用TEventUI结构的形式调用CControlUI类的Event函数来投递的.

duilib库分析: 消息流程分析的更多相关文章

  1. duilib库分析1.消息流程分析

    看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧. 1. 先看下CPaintManagerUI类的MessageLoop函数: void CPaintManagerUI ...

  2. 前端JS模版库kino.razor - 原理流程分析 - 改进版轮子RazorJs

    1.前言 从后台获取数据,在前端JS里面拼接字符串,不累吗?敢不敢找一款前端使使... 现在这种模板库比较多了,我用过的jquery-template .JsRender .听说过的一堆,还有各种MV ...

  3. 一、SDWebImage分析--库处理流程分析

    二.SDWebImage分析--源码具体分析 这阵子看了SDWebImage的实现跟源代码.也看了下网上的一些总结. 这里我自己画了个流程图来辅助理解下SDWebImage这个库的实现流程.相信也是有 ...

  4. duilib库分析4.第二篇UIBase

    DUiLib 源码分析 ——以UiLib 1.01版为分析目标 ——colin3dmax 分析于2011-6-16 19:44------------------------------------- ...

  5. Android之 MTP框架和流程分析

    概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介            对Mtp协议进行简单的介绍.第2部分 MTP框架            介绍 ...

  6. Android5 Zygote 与 SystemServer 启动流程分析

    Android5 Zygote 与 SystemServer 启动流程分析 Android5 Zygote 与 SystemServer 启动流程分析 前言 zygote 进程 解析 zygoterc ...

  7. openstack之虚拟机创建流程分析

    这篇博文静静的呆在草稿箱大半年了.假设不是由于某些原因被问到,以及由于忽略它而导致的损失,否则我也不知道什么时候会将它完毕.感谢这段时间经历的挫折,让我知道不足.希望你能给我更大的决心! 本文试图具体 ...

  8. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

  9. 报时机器人的rasa shell执行流程分析

      本文以报时机器人为载体,介绍了报时机器人的对话能力范围.配置文件功能和训练和运行命令,重点介绍了rasa shell命令启动后的程序执行过程. 一.报时机器人项目结构 1.对话能力范围 (1)能够 ...

随机推荐

  1. 请教DotNetBar控件中的CalendarView控件如何拖动当前的时间轴

    本人想拖动那个当前的时间轴或者让时间轴变动,因为那个时间轴默认的是当前时间.(就是那个黄色的线)

  2. poj 1085 Triangle War 博弈论+记忆化搜索

    思路:总共有18条边,9个三角形. 极大极小化搜索+剪枝比较慢,所以用记忆化搜索!! 用state存放当前的加边后的状态,并判断是否构成三角形,找出最优解. 代码如下: #include<ios ...

  3. Lua的require和module小结

    Lua的require和module小结  module特性是lua5.1中新增的,用于设置Lua文件自己的模块,最常用的方式是module(name,package.seeall),有时候lua文件 ...

  4. 【hdu3341-Lost's revenge】DP压缩+AC自动机

    题意:给定只含有A.G.C.T的n个模板串,一个文本串,文本串任意两个字母可互换位置,问最多能匹配多少个模板串.注意:匹配同一个模板串匹配了两次,ans+=2:(可重复) 题解: 原本想到一个简单dp ...

  5. 【zoj2562】反素数

    题意:给定一个数N,求小于等于N的所有数当中,约数最多的一个数,如果存在多个这样的数,输出其中最小的一个.(1 <= n <= 10^16) 题目:http://acm.hust.edu. ...

  6. Spark源码编译

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3822995.html spark源码编译步骤如下: cd /home/hdpusr/workspace ...

  7. hdu 1536 S-Nim

    题意:首先输入K 表示一个集合的大小  之后输入集合 表示对于这对石子只能去除这个集合中的元素的 个数 之后输入一个m表示接下来对于这个集合要进行m次询问 之后m行 每行输入一个n 表示有  n个堆  ...

  8. 【PSR规范专题(3)】PSR-2 代码风格规范

    [PSR规范专题(3)]PSR-2 代码风格规范 标签(空格分隔): PHP 转载自:https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-2-cod ...

  9. 本博客不再更新,欢迎访问本人托管在GitHub上的博客:www.wshunli.com

    本博客不再更新. 欢迎访问本人托管在GitHub上的博客:www.wshunli.com

  10. Java 虚拟机体系结构

    众所周知,Java源代码被编译器编译成class文件.而并不是底层操作系统可以直接执行的二进制指令(比如Windows OS的.exe文件).因此,我们需要有一种平台可以解释class文件并运行它.而 ...