duilib库分析日志 (二) : 消息流程分析
来源:互联网 发布:电力营销 知乎 编辑:程序博客网 时间:2024/06/16 06:15
看下CWindowWnd类与CPaintManagerUI类是咋进行消息分发的吧.
1. 先看下CPaintManagerUI类的MessageLoop函数:
void CPaintManagerUI::MessageLoop(){ MSG msg = { 0 }; while( ::GetMessage(&msg, NULL, 0, 0) ) { // 获取消息 if( !CPaintManagerUI::TranslateMessage(&msg) ) { // 消息过滤 ::TranslateMessage(&msg); ::DispatchMessage(&msg); // 分发到窗口的消息处理窗口中. 也就是调用CWindowWnd类的__WndProc函数或是__ControlProc函数. } }}消息第一次会由CPaintManagerUI类的TranslateMessage消息接收到.
2. 调用CWindowWnd::Create创建窗口. 完成以下操作:
1) 如果要子类下Window的控件(就是系统的控件, 而不是duilib的模拟控件), 就设置__ControlProc函数为消息回调函数.
2)不子类化, 就注册窗口类. 此时设置__WndProc为窗口消息处理回调函数.
3)用CreateWindowEx API函数创建窗口.
这里先不看子类化相关的, 我要先看明白标准的窗口创建过程. 这也操作后消息就会分发到__WndProc了,
3. 看下__WndProc函数的定义:
LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ CWindowWnd* pThis = NULL; if( uMsg == WM_NCCREATE ) {// 要在此消息中把类于窗口进行绑定 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);// 来自于CreateWindowEx函数的最后一个参数( 也就是CWindowWnd对象指针了 ) pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams); pThis->m_hWnd = hWnd; ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));// 设置到窗口的用户数据中 } else { pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); if( uMsg == WM_NCDESTROY && pThis != NULL ) { LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);// 收到窗口能处理到的最后一个消息了, 要进行收尾工作了. ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);// 取消类对象与窗口的绑定关系 if( pThis->m_bSubclassed ) pThis->Unsubclass(); pThis->m_hWnd = NULL; pThis->OnFinalMessage(hWnd); return lRes; } } if( pThis != NULL ) { return pThis->HandleMessage(uMsg, wParam, lParam); // 在此调用继承类的消息处理函数 } else { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); // 未绑定类对象, 就调用默认的窗口消息处理函数 }}
消息第二次就由__WndProc接收到, 然后再传到CWindowWnd类的HandlerMessage函数中.
3. 看看CWindowWnd类的继承类对于HandlerMessage虚函数的实现.
LRESULT CMainWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ){LRESULTlRes= 0;// 消息处理返回值.BOOLbHandled= TRUE;// 消息是否要继续往下传.switch ( uMsg ){case WM_CREATE:lRes= OnInitResource( bHandled ); break; // 进行初始化工作. 比如最重要的XML加载解析工作.default:bHandled= FALSE;}if ( bHandled ){return lRes;}if ( m_pm.MessageHandler( uMsg, wParam, lParam, lRes ) )// 传给CPaintManagerUI::MessageHandler函数进行具体的控件处理工作{return lRes;}return CWindowWnd::HandleMessage( uMsg, wParam, lParam ); // 没处理过的就调用CWindowWnd类的默认消息处理函数吧.}
在这里就是用户要按消息进行具体的处理了. 之后要传到CPaintManagerUI类对象的MessageHandler函数. 未处理的消息就要返回给CWindowWnd类的默认消息处理函数来处理了.
4. CPaintManagerUI类的TranslateMessage, MessageHandler函数的内容.
BOOL CPaintManagerUI::TranslateMessage(const LPMSG pMsg){ HWND hwndParent = ::GetParent(pMsg->hwnd); // 获取消息接收窗口的父窗口 UINT uStyle = GetWindowStyle(pMsg->hwnd); // 获取窗口的样式 LRESULT lRes = 0; for( int i = 0; i < m_aPreMessages.GetSize(); i++ ) { // 这个m_aPreMessage保存着CPaintManagerUI类对象. CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]); if( pMsg->hwnd == pT->GetPaintWindow() // 消息是否属于当前CPaintManagerUI绑定的窗口 || (hwndParent == pT->GetPaintWindow() && ((uStyle & WS_CHILD) != 0)) ) // 消息是否为当前窗口中窗口的消息, (如ActiveX控件 ) { if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return TRUE; // 此时就调用PreMessageHandler过滤函数. } } return FALSE;}m_aPreMessage为静态成员变量, 在CPaintManagerUI::Init进行窗口与此类绑定时添加到此变量中.
5. CPaintManagerUI::PreMessageHandler消息过滤函数.
BOOL CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/){ // 遍历当前的消息过滤列表. m_aPreMessageFilter的元素为IMessageFilterUI接口.只一个虚函数MessageHandler. // 用户可以添加此接口的继承类变量到m_aPreMessageFilters列表中. ( 调用AddMessageFilter函数实现 ) for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ ) { BOOL bHandled = FALSE; LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled); if( bHandled ) { return TRUE; } } // 以下是对几个按键消息的过滤. // WM_KEYDOWN 检查是否为VK_TAB键, 要进行控件焦点的移动. // WM_SYSCHAR 获取与wParam中的字符加速键匹配的控件, 并激活它. // WM_SYSKEYDOWN 生成控件事件( 用TEventUI来模拟 )}
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库分析日志 (二) : 消息流程分析
- duilib库-----消息流程分析
- duilib库分析: 消息流程分析
- duilib库分析: 消息流程分析
- duilib库分析: 消息流程分析
- Duilib中消息流程分析
- Duilib 源码分析之消息流程篇
- duilib库分析日志 (一) : 简单了解下duilib库
- Duilib分析
- duilib 消息流程
- RV日志流程分析
- DuiLib库简单分析 --- 1
- skynet流程分析二
- Duilib消息处理流程图解
- WM_NOTIFY消息流程实例分析
- TheONE消息转发流程分析
- Impala查询流程日志分析
- 简单的日志分析流程
- Qt Creator发布release软件相关注意事项 .
- oracle 日期加减方法
- java中定时JOB的实现方式
- 查看entity生成的sql语句
- 实践中探索Android智能手机系统------ROM分区
- duilib库分析日志 (二) : 消息流程分析
- zhouqq pg 文档
- 程序在 编译期,链接期, 运行期各执行哪些操作?
- Windows MFC 窗口消息
- 火星一下----为 URLDownloadToFile 实现进度条
- onNewIntent调用时机
- 在Tomcat中部署war
- Splash Screens - 启动页面设置
- 隐藏状态栏