博客已迁移至:http://kulv.sinaapp.com/,这里不再使用

金山卫士开源代码----消息机制浅析 (上)

代码地址:http://download.csdn.net/source/3301518


今天简化了金山的开源代码,用来学习一下,先谢谢金山的开源精神了,呵呵···直接弄最简单的,窗口见下图,关键代码如下,全部的代码放附件里吧。分析中关于累的继承机制等没有详细的说明了,在函数申明中我会用SON: public BASE ::Func() 的方式指出的.今天主要学习一下其消息机制和路由。因为没有学过ATL,所以理解错了希望大家指教一下哦···
先谢谢了,呵呵···


/// //Main.cpp int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) {if ( FAILED( _Module.Init( hInstance ) ) )return -1;::CoInitializeEx( NULL , COINIT_APARTMENTTHREADED );_Module.Run( );_Module.Uninit( );::CoUninitialize( );return 0; }HRESULT KAppModule::Init( HINSTANCE hInstance ) {HRESULT hRet = __super::Init( NULL, hInstance );if ( FAILED(hRet) )return hRet;return hRet; } HRESULT KAppModule::Run( ) {_InitUIResource( );//加载各种资源,从XML中if ( m_hModRichEdit2 == NULL )m_hModRichEdit2 = ::LoadLibrary( _T( "RICHED20.DLL" ) );//显示对话框CKulvDlg wdlg ;return wdlg.DoModal( ) ; }void KAppModule::_InitUIResource() {//加载各种资源,从XML中BkFontPool::SetDefaultFont(_T("宋体"),-12);BkSkin::LoadSkins(IDR_SKIN_DEF);BkStyle::LoadStyles(IDR_STYLE_DEF);BkString::Load(IDR_STRING_DEF); }//DLG.h #pragma once class CKulvDlg: public CBkDialogImpl<CKulvDlg> { public:CKulvDlg(): CBkDialogImpl<CKulvDlg>(IDR_WARMING_DLG){//IDR_WARMING_DLG : 107, "res//warning_dlg.xml")}~CKulvDlg(); protected:BOOL OnInitDialog(CWindow /*wndFocus*/ , LPARAM /*lInitParam*/ );void OnBtnClose( );void OnBtnClickText( ); public:BK_NOTIFY_MAP(IDC_RICHVIEW_WIN)BK_NOTIFY_ID_COMMAND(100, OnBtnClose)BK_NOTIFY_ID_COMMAND(101, OnBtnClickText)BK_NOTIFY_MAP_END()BEGIN_MSG_MAP_EX(CKulvDlg)MSG_BK_NOTIFY(IDC_RICHVIEW_WIN)CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>)MSG_WM_INITDIALOG(OnInitDialog)END_MSG_MAP()}; //DLG.cpp #include "stdafx.h" #include "DLG.h"CKulvDlg::~CKulvDlg(){ }BOOL CKulvDlg::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/){return TRUE; }void CKulvDlg::OnBtnClose(){__super::EndDialog(IDOK); }void CKulvDlg::OnBtnClickText(){DontShowWindow() ;CString str = CString(__FILE__) ;str.Format(TEXT("%s : %d"),str.GetBuffer() , __LINE__) ;MessageBox(str); }


/
/*我们来看如下消息机制的宏替换,容易看出,其酷像MFC的宏!开始我还看错了呢,呵呵*/

BK_NOTIFY_MAP(IDC_RICHVIEW_WIN) BK_NOTIFY_ID_COMMAND(100, OnBtnClose) BK_NOTIFY_ID_COMMAND(101, OnBtnClickText) BK_NOTIFY_MAP_END()

/*如上宏声明替换后实际上就是在类里面添加了下面这样的消息分配机制也就是根据控件的ID来一个个比较,然后调用相应控件的处理函数,这个函数就是我们在宏申明的时候指定的。
*/

LRESULT CKulvDlg::OnBkNotify_1000(LPNMHDR pnmh) { UINT_PTR uCode = pnmh->code; if (BKNM_COMMAND == uCode && 100 == ((LPBKNMCOMMAND)pnmh)->uItemID) { OnBtnClose(); return TRUE; } if (BKNM_COMMAND == uCode && 101 == ((LPBKNMCOMMAND)pnmh)->uItemID) { OnBtnClickText(); return TRUE; } SetMsgHandled(FALSE); return FALSE; }

/// /// /*在对话框类中,还有如下宏申明,看看其到底是什么吧*/ BEGIN_MSG_MAP_EX(CKulvDlg) MSG_BK_NOTIFY(IDC_RICHVIEW_WIN) CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>) MSG_WM_INITDIALOG(OnInitDialog) END_MSG_MAP()/*替换后变成如下代码:*/ //BEGIN_MSG_MAP_EX(CKulvDlg) public:BOOL m_bMsgHandled; /* "handled" management for cracked handlers */BOOL IsMsgHandled() const { return m_bMsgHandled; } void SetMsgHandled(BOOL bHandled) { m_bMsgHandled = bHandled; //设置消息处理状态} BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) { //本对话框所有的消息处理从这开始BOOL bOldMsgHandled = m_bMsgHandled; BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); m_bMsgHandled = bOldMsgHandled; return bRet; } BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) { //下面就是短短的消息长征了,相对于复杂的MFCBOOL bHandled = TRUE; hWnd; uMsg; wParam; lParam; lResult; bHandled; switch(dwMsgMapID) { case 0://MSG_BK_NOTIFY(IDC_RICHVIEW_WIN)if (uMsg == WM_NOTIFY && 1000 == ((LPNMHDR)lParam)->idFrom) { //第一步,如果是控件通告消息,那么消息处理函数是://OnBkNotify_1000,别忘了,这个东西我们上面说过的,那里还有所以的控件消息映射//实际上就是根据ID,一个个找。SetMsgHandled(TRUE); lResult = OnBkNotify_1000((LPNMHDR)lParam); if(IsMsgHandled()) return TRUE; }//CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>)if( CBkDialogImpl<CKulvDlg>::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult) ) return TRUE; //给父类处理一下,我不明白为何这么早给父类干嘛,如果有些我们要自己处理呢?哦,这样没事的//MSG_WM_INITDIALOG(OnInitDialog)if (uMsg == WM_INITDIALOG) { //实际上父类没有处理WM_INITDIALOG消息,所以一定传到这里了,进行自定义初始化SetMsgHandled(TRUE); lResult = (LRESULT)OnInitDialog((HWND)wParam, lParam); if(IsMsgHandled()) return TRUE; }//MSG_WM_INITDIALOG(OnInitDialog)break; default://用户ID写错了,那么在输出窗口打印错误消息,以便调试ATLTRACE(ATL::atlTraceWindowing, 0, _T("Invalid message map ID (%i)/n"), dwMsgMapID); ATLASSERT(FALSE); break; } //消息“长征正式结束”return FALSE; }

/*这个消息分配方法清除了,那驱动在哪呢?对,从源头开始找吧。下面的函数一般在Winmain里面调用,是主要的函数,其他都是些初始化什么的*/

HRESULT KAppModule::Run( ){_InitUIResource( );//这地方初始化各种UI库什么的,下回再仔细看看//金山界面库是如何用XML实现的,不过应该基本也是封装各种Win32 APIif ( m_hModRichEdit2 == NULL )m_hModRichEdit2 = ::LoadLibrary( _T( "RICHED20.DLL" ) );CKulvDlg wdlg ;return wdlg.DoModal( ) ;//从这里开始吧,我们的自定义子类一般不会重定义这个函数,到父类中,看下面:}//CBkDialogImpl : public CWindowImpl <T, TBase, TWinTraits>UINT_PTR CBkDialogImpl::DoModal(HWND hWndParent = NULL, LPRECT rect = NULL){//····这里省略··字//Create函数加载了XML资源,然后设置了窗口什么的,下回在看这部分,专注,专注···HWND hWnd = Create(hWndParent, rect);//····这里省略··字_ModalMessageLoop();//···看下面//····这里省略··字DestroyWindow();return m_uRetCode;}void CBkDialogImpl::_ModalMessageLoop(){BOOL bRet;MSG msg;for(;;){//这个循环很长····直到接收到WM_QUIT,break为止if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)){//PeekMessage和GetMessage什么区别去了?对,后者过门不入if (WM_QUIT == msg.message)break;}//···::TranslateMessage(&msg);::DispatchMessage(&msg);}}

/*这···无限循环取得消息,这已经到操作系统API层了,那么具体的DispatchMessage是发给哪个函数去分发了呢??对,某大作说过,Create,RegisterWindow,那一定有一个消息驱动函数,我们得告诉操作系统的,而且是个回调函数,by the way ,为什么要做成回调函数?直接在dispathMessage 里我们调不就行了吗?···恩,侯捷说过,操作系统想有点控制权。
 下面继续*/

/*先说下哦,因为我没看过ATL,WTL,所以不知道哪些部分是属于库的,暂且就这样走到根吧···
 经过消息跟踪,发现每次DispatchMessage的时候,下一个被调用的用户自定义函数是:
 c:/Program Files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin.h中的3072行:
 LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)*/

template <class TBase, class TWinTraits>LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)_AtlWinModule.ExtractCreateWndData();//···pThis->m_hWnd = hWnd;pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);WNDPROC pProc = pThis->m_thunk.GetWNDPROC();WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);//···return pProc(hWnd, uMsg, wParam, lParam);}virtual WNDPROC template <class TBase, class TWinTraits>LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::GetWindowProc(){return WindowProc;}

/*实际上StartWindowProc调用的是WindowProc
 c:/Program Files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin.h中的3072行:
 LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 WindowProc,对,这个函数名我们非常熟悉了!!
 对,由此可知,StartWindowProc一定是我们要找的回调函数,CALLBACK不就告诉我们了嘛,呵呵,其申明也确实是静态的:
 static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 下面贴一下代码看看:
 */

template <class TBase, class TWinTraits>LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){/*把窗口句柄强制转换成基类指针,为什么呢?首先这个窗口句柄应该是窗口类的首地址?这是window系统的实现方式,许多句柄其实都是虚拟地址*/CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;//····此处省略几行/*注意,ProcessWindowMessage是一个虚函数,所以···实际上调用的是我们自定义的窗口类!!于是消息路由跑到我们的CKulvDlg中了,这一点之前的宏展开说过。不过还得提一下,消息从CKulvDlg中会一步步的往基类中走只要没被处理,最终如果运气实在···,还没处理,那就返回吧···*/BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);//····if(!bRet){//如果消息还没被处理,那么进入DefWindowProc,如果不是WM_NCDESTROYif(uMsg != WM_NCDESTROY)lRes = pThis->DefWindowProc(uMsg, wParam, lParam);else{//下面准备退出了// unsubclass, if neededLONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);lRes = pThis->DefWindowProc(uMsg, wParam, lParam);if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);// mark window as destryed//上面一注释不是我写的哦,ATL设计者竟然不小心把destroyed写错了,呵呵···pThis->m_dwState |= WINSTATE_DESTROYED;}}//····return lRes;}/*值得说明一下的是: ProcessWindowMessage是一个虚函数.的吗?宏定义里面没写virtual,但是其基类里面有就够了,如下基类CBkWindow中有如下宏定义,确实是虚函数,放心了。*/class CBkWindow BKWIN_BEGIN_MSG_MAP(): public CBkObject #define BKWIN_BEGIN_MSG_MAP() /protected: /virtual BOOL ProcessWindowMessage( /HWND hWnd, UINT uMsg, WPARAM wParam, /LPARAM lParam, LRESULT& lResult) /{


/*读者看到这也基本明白了这消息映射的路由。不过总感觉有点别扭,为什么消息处理函数是StartWindowProc??? 谁告诉windows的?操作系统怎么知道的??那咱们继续吧:没记错的话我们之前说DoModal的时候有如下一句
 HWND hWnd = Create(hWndParent, rect);
  //····这里省略··字 被我故意省略了很多字···
 下面补上吧,看代码
  */

见下文http://blog.csdn.net/hw_henry2008/archive/2011/05/22/6438183.aspx

金山卫士开源代码----消息机制浅析 (上相关推荐

  1. 《在路上 …》 金山卫士开源 , 人生很多感慨

    最近写日记少了很多, 主要是很多情绪化的东西, 都汇入了某条有去无回的地下河. 好吧, 不说这些, 来说说金山卫士开源. 相比360安全卫士那种作秀式的开源 (代码只对极少极少的人开放, 隐隐藏藏), ...

  2. 金山卫士开源软件之旅(十) KSafeMainproject的分析 1

    上一次看金山开源到如今已有一两个月了.期间看到QQ群里大家对它非常是热情. 近期有时间想看看金山的主界面projectKSafeMain,自己水平有限,总结的东西浅显.但还是愿意拿来与大家分享.希望对 ...

  3. 金山卫士开源软件之旅(十) KSafeMain工程的分析 1

    上一次看金山开源到现在已有一两个月了.期间看到QQ群里大家对它很是热情. 最近有时间想看看金山的主界面工程KSafeMain,自己水平有限,总结的东西浅显.但还是愿意拿来与大家分享.希望对大家有帮助. ...

  4. Windows 消息机制浅析

    Windows 消息机制浅析 1.       Windows 的历史 中国人喜欢以史为鉴,而事实也确实是,如果你能知道一件事情的来龙去脉,往往可以更容易地理解事物为什么会表现为当前这样的现状.所以, ...

  5. 《金山卫士开源--让互联网拥抱安全》语音互动实录

    12月22日,金山网络安全技术研发中心过程改进经理,参与了主题<金山卫士开源--让互联网拥抱安全>的公开YY语音,与网友们进行了深度的互动,为广大网友答疑解惑有关金山卫士的详情. 嘉宾简介 ...

  6. 分享下金山卫士的代码

    自从金山卫士的代码部分开源以来,基于它出现了各种软件,有侧重界面库的,如SOUI,有侧重电脑安全管理的,下面是我维护的版本的部分截图: 主界面 垃圾清理 ARP防火墙 隐私保护器 对于广大开发者尤其是 ...

  7. 金山卫士开源软件之旅(二) 简单教程:如何创建一个基于金山卫士界面库的工程

    完整解决方案代码压缩包: test_full.zip (267.59 KB) 参考: http://bbs.code.ijinshan.com/thread-1391-1-1.html 为了让更多的朋 ...

  8. 金山卫士开源---kclear 卫士垃圾清理

    金山卫士的开源已经进行了好长时间了,现在已经开放第六批源码"kclear 卫士垃圾清理". 下载源码,使用VS2010打开,自动转换解决方法之最新. 首先,源代码是需要atl支持的 ...

  9. 金山卫士开源系列讲座之一:揭秘卫士如何优化系统

    你的电脑开机速度快不快?你的系统运行速度为何变慢?虽然我们整天用电脑,但很多人对此不明所以,或者知其然而不知其所以然. 作为国内专业的主流安全管理软件,金山卫士拥有简便强劲的系统优化功能,包括开机加速 ...

最新文章

  1. 谈谈JIT编译器和本机影像生成器(NGen.exe)
  2. Kotlin开发springboot项目(一)
  3. 2021-10-11 程序人生 -感想随笔
  4. UVa OJ 120
  5. 前端学习(3029):vue+element今日头条管理-顶部导航栏布局
  6. 【LightOJ - 1027】A Dangerous Maze(概率dp,数学期望)
  7. python generator转为list_Python中的 List Comprehension 以及 Generator
  8. C语言程序设计的特点
  9. PSARDumper DA发布PSP3000解密工具
  10. 面试时,如何巧妙回答跳槽问题
  11. 如何在Keil中的添加和使用STC芯片型号
  12. Ubuntu18.04创建快捷方式
  13. 根据表一和表二写出查询结果如表三的sql语句
  14. Ubuntu1604上使用Qt远程调试arm开发板
  15. 最新ubuntu搭建公网个人邮件服务器(基于postfix,dovecot,mysql)
  16. 依图科技从科创板“退赛”:三年半累计亏损72亿,研发费用高企
  17. Excel 和 python 使用梯度下降法分别求【极小值点】【线性回归问题】
  18. 使用google map v3 api 开发地图服务
  19. 全球十大资质正规现货黄金交易平台排名榜单(最新版汇总)
  20. 压力测试+接口测试(工具jmeter)

热门文章

  1. 行亦谦ACM自闭之旅第三周
  2. 泛型总结(通俗易懂)
  3. 【计算几何】判断线段相交(跨立实验)
  4. java 逻辑运算符(韩顺平)
  5. ubuntu 上 ufw 配置
  6. Jupyter Notebook打不开,点了后黑窗闪动了下
  7. 如何把自己的知识、经验、才华高效变现
  8. xform的应用——MEL
  9. 关于互联网内容服务的公共协议(ICCP)[1]
  10. PADS的快捷键总结