手把手分析 mfc 程序创建 代码执行流程

程序流程

1.先全局变量theapp;

2.AfxWinMain,包括执行InitApplication、InitInstance(一般会重写)、Run

3.在InitInstance 会create 窗口,通过LoadFrame(多文档,只创建CMDIFrameWnd,至于cdoc、CMDIChildWnd、cview是执行ProcessShellCommand创建的)或者 ProcessShellCommand(单文档,同时创建cdoc、cframe、cview)。‘’

其实多文档也执行ProcessShellCommand。ProcessShellCommand用来创建先cdoc、再frame.同时在创建frame的时候,通过调用CFrameWnd::Create函数,发出WM_CREATE消息。响应CMainFrame::OnCreate函数,

从而响应CFrameWnd::CreateView,执行CreateView,创建cview.

单文档:

CMFCApp::InitInstance()  -> ProcessShellCommand -> OnFileNew()->CDocManager::OnFileNew()->OpenDocumentFile (因为是虚函数,所以执行子类的CSingleDocTemplate::OpenDocumentFile)  ->CreateNewDocument(创建CDocument对象)  ->CreateNewFrame ->CFrameWnd::LoadFrame(因为是虚函数,会先执行CMainFrame::LoadFrame,最后执行CFrameWnd::LoadFrame)->CFrameWnd::GetIconWndClass ->PreCreateWindow(因为是虚函数,会先执行CMainFrame::PreCreateWindow,最后执行CFrameWnd::PreCreateWindow)->AfxRegisterWndClass ->AfxRegisterClass(注册窗口,其中回调函数是DefWindowProc) ->CFrameWnd::Create ->CWnd::CreateEx ->PreCreateWindow(又一次,因为是虚函数,会执行CMainFrame::PreCreateWindow) ->AfxHookWindowCreate(通过SetWindowsHookEx钩子函数->_AfxCbtFilterHook ->AfxGetAfxWndProc ->AfxWndProc ->AfxCallWndProc ->WindowProc) ->CreateWindowEx(真正创建窗口,会发出WM_CREATE,从而进入到CMainFrame::OnCreate该函数创建cview、工具栏、状态栏、属性栏等。)->CFrameWndEx::OnCreate ->CFrameWnd::OnCreate ->CFrameWnd::OnCreateHelper ->CFrameWnd::OnCreateClient ->CWnd* CFrameWnd::CreateView ->CWnd::Create (和回到上面Create 一样了) ->CWnd::CreateEx ->AfxHookWindowCreate ->CreateWindowEx

上面这些函数被执行完后,回到winapp的InitInstance,执行下面的ShowWindow和UpdateWindow。

InitInstance执行完后,回到afxwinmain。执行run,进入消息循环。

即下面的部分具体解读

其实在CWnd::Create函数中也会先调

1.CWnd::Create -> CWnd::CreateEx-> PreCreateWindow ->AfxEndDeferRegisterClass ->AfxRegisterClass 进行窗口类注册

2. CFrameWnd::Create -> CWnd::CreateEx -> AfxHookWindowCreate -> ::SetWindowsHookEx(WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId()); ->CALLBACK _AfxCbtFilterHook -> AfxGetAfxWndProc ->CALLBACK AfxWndProc ->AfxCallWndProc

->WindowProc                  所以可以在cwnd类的虚函数WindowProc 重写实现对应的功能

3.最后调用CreateWindowEx进行真正创建窗口。创建成功后,指向一个值的指针,该值传递给窗口WM_CREATE消息。该值通过在lParam参数中的CREATESTRUCT结构传递。如果应用程序调用CreateWindow创建一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构。简单一句话:窗口产生之际发出WM_CREATE消息,响应afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);即执行CMainFrame::OnCreate,在该函数创建cview、工具栏、状态栏、属性栏等。->CMainFrame::OnCreate ->CMDIFrameWnd::OnCreate->CFrameWnd::OnCreateHelper

在MFC 单文档或者多文档模式CMainFrame::Create是通过CMainFrame::LoadFrame调用起来的。通过ProcessShellCommand 从而生成cdoc、cview等类。而LoadFrame是在应用程序类winapp的InitInstance函数被调用。

所以在整个CMainFrame类的执行先后顺序是:LoadFrame -> Create ->PreCreateWindow -> WindowProc -> OnCreate   

上面这些函数被执行完后,回到winapp的InitInstance,执行下面的ShowWindow和UpdateWindow。

InitInstance执行完后,回到afxwinmain。执行run,进入消息循环。

说明创建每个cwnd类,都会创建钩子函数,回调函数。

多文档

CdwdApp::InitInstance -> CMainFrame::LoadFrame ->CMDIFrameWndEx::LoadFrame -> CMDIFrameWnd::LoadFrame ->CFrameWnd::LoadFrame(其实这部分和上面的单文档一样的)-> CFrameWnd::GetIconWndClass ->PreCreateWindow(因为是虚函数,会先执行CMainFrame::PreCreateWindow,最后执行CFrameWnd::PreCreateWindow)->>AfxRegisterWndClass ->AfxRegisterClass(注册窗口,其中回调函数是DefWindowProc) ->CFrameWnd::Create ->CWnd::CreateEx->PreCreateWindow(又一次,因为是虚函数,会执行CMainFrame::PreCreateWindow)-> AfxHookWindowCreate(通过SetWindowsHookEx钩子函数->_AfxCbtFilterHook ->AfxGetAfxWndProc ->AfxWndProc ->DefWindowProc) ->CreateWindowEx(真正创建窗口,会发出WM_CREATE,从而进入到CMainFrame::OnCreate该函数创建cview、工具栏、状态栏、属性栏等。->CMainFrame::OnCreate ->CMDIFrameWndEx::OnCreate -> CFrameWnd::OnCreate -> CFrameWnd::OnCreateHelper -> OnCreateClient(因为是虚函数,实际执行CMDIFrameWndEx::OnCreateClient,也是多文档和单文档的区别,因为在单文档子类没有重写该虚函数) - >CMDIFrameWnd::OnCreateClient -> CMDIFrameWnd::CreateClient ->CreateWindowEx(穿件mdi 客户区m_hWndMDIClient,) ->ProcessShellCommand(参考单文档) ->CWinApp::OnFileNew->OpenDocumentFile(因为该函数是虚函数,实际执行的是CMultiDocTemplate::OpenDocumentFile)->CreateNewDocument(创建文档)-> CDocTemplate::CreateNewFrame ->LoadFrame(因为其是虚函数,实际执行CMDIChildWnd::LoadFrame,也是和单文档的区别) -> CFrameWnd::GetIconWndClass->PreCreateWindow(该函数为虚函数,实际执行CChildFrame::PreCreateWindow)  ->AfxRegisterWndClass ->AfxRegisterClass  ->Create (该函数为虚函数,实际执行CMDIChildWnd::Create) ->PreCreateWindow (又一次,该函数为虚函数,实际执行CChildFrame::PreCreateWindow) ->AfxHookWindowCreate(通过SetWindowsHookEx钩子函数->_AfxCbtFilterHook ->AfxGetAfxWndProc ->AfxWndProc ->AfxCallWndProc ->WindowProc)->SendMessage(WM_MDICREATE) ->CMDIChildWnd::OnCreate(在SendMessage函数到OnCreate之间,中间经历很多消息映射、命令传递等操作,即执行WindowProc回调函数)->CFrameWnd::OnCreateHelper ->CFrameWnd::OnCreateClient ->CFrameWnd::CreateView ->CWnd::Create ->CWnd::CreateEx ->AfxHookWindowCreate(通过SetWindowsHookEx钩子函数->_AfxCbtFilterHook ->AfxGetAfxWndProc ->AfxWndProc ->AfxCallWndProc ->WindowProc)-> CreateWindowEx

document template  

document/view

程序每打开一份文件(数据),就产生3份对象。

1.document

2.view //外围必须封装一个外框窗口作为舞台

3.CMDIChildWnd(作为view 的外框窗口),当是多文档模式时。如果是单文档则直接是CFrameWnd。

所以多文档的流程是

手把手分析 mfc 程序创建 代码执行流程_第1张图片

在cview类中,消息函数onpaint调用ondraw虚函数。

手把手分析 mfc 程序创建 代码执行流程_第2张图片

CDocument:

1.void UpdateAllViews(CView* pSender, LPARAM lHint = 0L,  CObject* pHint = NULL);   //调用UpdateAllViews会执行CView::OnUpdate ->Invalidate ->产生wm_paint -> onpaint ->ondraw

2.virtual BOOL OnNewDocument();  //该函数是在OpenDocumentFile 中创建好文档、框架窗口、视图后,被调用的。

CView:

  1. virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);   //利用Invalidate(TRUE)把窗口设置为重绘区(无效区)并产生wm_paint,会执行onpaint,执行ondraw.

  2.virtual void OnInitialUpdate(); // called first time after construct   构造函数生成本类的对象,但没有产生窗口,OnCreate后窗口产生, 然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化.然后再执行OnDraw

  3.virtual void OnDraw(CDC* pDC) = 0;  //如果想在ondraw前,调整dc,可以先调用重写onpreparedc,再调用OnDraw。

手把手分析 mfc 程序创建 代码执行流程_第3张图片

  4. CDocument* GetDocument() const;

  5.CFrameWnd* GetParentFrame() const;

CFrameWnd:

1.CView* GetActiveView() const;           // active view or NULL

2.virtual CDocument* GetActiveDocument();

前面说doc和view是一一对应,现在又说一个doc可以对应多个view?

理解:确实一个doc对应一个view,并且是通过CMultiDocTemplate来进行管理维护,那么如果想一个doc对应多个view,

1.需要创建多个CMultiDocTemplate对象,并且指定RUNTIME_CLASS都是用一个doc,而使用不同的view。

2.因为应用程序开始默认只执行一次OpenDocumentFile,那么即只创建一次doc、frame、view.并且需要改造重写OnFileNew函数,让第一个CMultiDocTemplate对象执行OpenDocumentFile。

3.这时候就不需要再创建doc,只需要创建frame(view也在该过程创建的)。所以可以重写cdoc::OnNewDocument(),调用CreateNewFrame。

所以就可以一个doc可以对应多个view。
 

你可能感兴趣的:(MFC,windows)