打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
MFC一些小总结

1.

      MDI跟SDI在运行机制上还是不一样的,不过大致路径都差不多。

     SDI里有Document/View support的AppWizard生成的WinApp::InitInstance里是没有下面这些代码的。下面这些设计到窗口初始化,注册,创建功能的代码在MDI和SDI中      无Document/View support中才有。

     CMainFrame* pMainFrame = new CMainFrame;
      if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
      return FALSE;

    那SDI中是如何LoadFrame,如何Create的,答案在if (!ProcessShellCommand(cmdInfo))return FALSE里,

    调用过程大概是这样的:

   ProcessShellCommand-> (FileNew)OnCmdMsg-> _AfxDispatchCmdMsg -> ((AfxSigCmd_v):pTargrt->*mmf.pfnCmd_v_u)

   ->CWinApp::OnFileNew ->mpDocument->OnFileNew->CDocManger->OnFileNew->pTemplate->OpenDocumentFile->

   CreateNewFrame->CFrameWnd::LoadFrame

   中间设计到动态创建初始化DOC或者Frame。过程就是这样的,没有Frame的时候就用Filenew创建一个Frame出来。后面的过程就一样了。

   CFrameWnd::LoadFrame->CFrameWnd::Create->CWnd::CreateEx->CreateWindowEx,CreateWindowEx(AfxCtxCreateWindowEx)发出WM_CREATE消息被滤网函数拦截,由于自己的程序改写了OnCreate函数,所以到达MyFrameWnd::OnCreate函数,在这个函数内部有调用了父类FrameWnd::OnCreate->CreateView(CFrameWnd::OnCreate->CFrameWnd::OnCreateHelper->CFrameWnd::OnCreateClient->CFrameWnd::CreateView),这个函数还包括工具栏和状态栏的创建,当然这也是需要自己修改的。

CFrameWnd::CreateView->CWnd::Create->回到CWnd::CreateEx->CreateWindowEx(AfxCtxCreateWindowEx),再次发出WM_CREATE消息,到达CView::OnCreate(非虚函数)(如果自己在CMyView中自己添加了WM_CREATE的消息和消息响应函数,就到达CMyView中然后进入CView::OnCreate)。最后都结束后仍返回MyFrameWnd::OnCreate函数。

2.  

    消息响应和命令传递

   首先看看类关系图:

整个消息传递的网络,在消息产生前已经由BEGIN_MESSAGE_MAP/END_MESSAGE_MAP/DECLARE_MESSAGE_MAP三个宏形成了一张大大的关系网。为消息的传递做好了准备。

然后说说windows消息分类:

  • 标准消息    除了WM_COMMAND之外所有WM开头的消息,派生自CWnd类
  • 命令消息    来自菜单、加速键或工具栏按钮。以WM_COMMAND形式呈现,通过ID区分不用命令消息。
  • 通告消息    由控件比如按钮点击,列表框选择等产生的。也以WM_COMMAND形式呈现。
所以只有从CWnd派生的类(CView和CFrameWnd)可以接受标准消息,例如WM_LButtonDown这样的消息。
而其它的例如从CDocument派生的类只能接受COMMAND命令消息。

下面总结一下消息传递。

消息传递有处理函数本身有一个默认的DefWindowProc函数,但是只在找不到消息的时候才调用它。MFC根据一系列的调用在消息传递时做了替换,毕竟一个DefWindowProc又不知道我们要处理什么。从CWnd::CreateEx函数中设置Hook函数滤网函数,又调用WindowProc函数做替换。WindowProc中由OnWndMsg函数根本不同消息类型做不同路径的传递,找到消息就做相应的处理,最终循环一个圈还没找到只能回到原始的DefWindowProc函数去处理了。

如果消息是标准消息,很简单,直接通过过程函数由子类到父类追溯逐次查消息映射表就可以了(下图).如果没有找到就转给DefWindowProc函数。查找消息的过程由已经建立好的消息网络进行,在循环中pMessage->pBaseMap,由AfxFindMessageEntry函数根据早先的AFX_MSGMAP_ENTRY结构中的nSig直到AfxSig_end,还有nID,nCode.

如果是命令消息,就复杂了。

先进入1 OnCommand()

CWnd::WindowProc->vitual OnCommand()

                                            if this->CMyFrameWnd->CFrameWnd::OnCommand()(内部调CWnd)->CWnd::OnCommand()

                                         else this->CMyView->CMyView::OnCommand()(没有改写,调CWnd)->CWnd::OnCommand()

再进入OnCmdMSG,假设当前this->CMyFrameWnd

于是次序有了

  •  CFrameWnd::OnCmdMsg->CView::OnCmdMsg->CWnd::OnCmdMsg->CCmdTarget::OnCmdMsg
  • 如果找到消息就处理,没有找到就返回到刚刚的CView::OnCmdMsg调用中,调用->CDocument::OnCmdMsg->CCmdTarget::OnCmdMsg
  • 如果找到消息就处理,没有找到就结束了CView::OnCmdMsg的调用,退回到CFrameWnd::OnCmdMsg的调用中,调用->CWnd::OnCmdMsg->CCmdTarget::OnCmdMsg
  • 如果找到消息就处理,没有找到就退回到CFrameWnd的调用中,调用->CWinApp::OnCmdMsg->CCmdTarget::OnCmdMsg
  • 如果这样还是没找到,就退回到上图中的CWnd::WindowProc,调用->::DefWindowProc
传递的过程设计到View/Document/DocumentTemplate等等. 
为什么命令消息这么曲折的传递的,其实很简单,能发出命令消息的就是UI,菜单或者工具栏啊等等,所以一定从Frame出发,然后检查自己的View有没有对应发出命令的事件发生,View没有就给Document看看数据是不是有什么事件发生,没有就回到Frame窗口在查看,最后交给WinApp应用程序,最后还是没有只好有系统处理了。

至此全部结束.本人懒,贴张图,说明整个过程

3. 现在来说说整个MFC的流程:

  WinApp pApp(执行构造函数,做一些初始化工作)—>AfxWinMain()函数(_tWinMain)内调用下面函数->AfxWinInit()->CWinApp::InitApplication()->CWinApp::InitInstance()->CWinApp::Run()

AfxWinInit():主要进行内部初始化工作

CWinApp::InitApplication():主要完成DocManager和Document Template初始工作

在CWinApp::InitInstance()中:

主要是new CMyFrameWnd->CMyFrameWnd::Create()->CFrameWnd::Create()->CWnd::CreateEx()->CFrameWnd::PreCreateWindow->AfxAPI AfxEndDeferRegistClass->AfxRegisteredClass RegisterwithIcons->::RegisterClass->CreateWindowEx->发出WM_CREATE消息->MainFrame::OnCreate()->FrameWnd::OnCreate()->CreateView()

 到这就正如1中所说:CFrameWnd::CreateView->CWnd::Create->回到CWnd::CreateEx->CreateWindowEx(AfxCtxCreateWindowEx),再次发出WM_CREATE消息,到达CView::OnCreate(非虚函数)(如果自己在CMyView中自己添加了WM_CREATE的消息和消息响应函数,就到达CMyView中然后进入CView::OnCreate)。最后都结束后仍返回MyFrameWnd::OnCreate函数。

最后是->ShowWindow()->UpdateWindow()

至此结束

需要说明的是我们利用MFC做一个启动画面效果的时候有一种方法是从Wnd中派生出一个类CSplashWnd,在里面实现Oncreate,Onpaint这样消息响应函数,而且在InitInstance()里面进行调用。例如CreateEx(从上面流程可以知道如果有类派生自CWnd,并且重新实现了CreateEx,那么肯定执行派生类的),重新showwindow,updatewindow。这样就可以有一个先启动的画面了。 而且由1知道WM_CREATE消息是在loadframe时发出的(CreateEx发出),而WM_PAINT是Updatewindow时发出的。所以在InitInstance()中我们实现的函数要放在loadframe()之前才能产生预想的效果。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
消息映射和命令传递(转)
深入浅出MFC学习笔记(第9章:消息映射与命令传递。)
第五章 MFC对象的创建
MFC 机制
Windows编程之MFC窗口程序浅析
MFC窗口类函数的概括
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服