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消息分类:
下面总结一下消息传递。
消息传递有处理函数本身有一个默认的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
于是次序有了
至此全部结束.本人懒,贴张图,说明整个过程
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()之前才能产生预想的效果。
联系客服