InitialUpdateFrame()跟踪

在CSingleDocTemplate::OpenDocumentFile()或CMultiDocTemplate::OpenDocumentFile()的过程中,前者根据需要CreateNewFrame(),后者则一直CreateNewFrame()。之后需要调用CDocTemplate::InitialUpdateFrame()。

 

CDocument* CSingle/MultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)
{

...

       CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);

...

      InitialUpdateFrame(pFrame, pDocument, bMakeVisible);//因此对于单文档来说,同一个视图的OnInitialUpdate()将被调用多次!(CeateNewFrame里的LoadFrame和InitialUpdateFrame会发出了WM_INITIALUPDATE消息)而多文档每次都创建新的文档、子框架窗口和视图,因此OnInitialUpdate只会被调用两次。
...

}

void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)
{

       // just delagate to implementation in CFrameWnd

       pFrame->InitialUpdateFrame(pDoc, bMakeVisible);

}

 

void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)

{

       // if the frame does not have an active view, set to first pane

       CView* pView = NULL;

       if (GetActiveView() == NULL)//对于单文档,只有第一次为NULL;对于多文档,必然为NULL,即此时还没有活动视

       {

              CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);

// CWnd* GetDescendantWindow( int nID, BOOL bOnlyPerm = FALSE ) const;

返回一个CWnd对象的指针,如果没有找到子窗口,则返回NULL。nID指定了要获取的控件或子窗口的标识符。bOnlyPerm指定了返回的窗口是否可以是临时的。如果为TRUE,则只能返回永久性的窗口;如果为FALSE,则该函数可以返回临时窗口。调用这个函数以找到给定的ID所指定的后代窗口。这个成员函数搜索整个子窗口树,并不仅是直接子窗口。

              if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))

              {

                     pView = (CView*)pWnd;

                     SetActiveView(pView, FALSE);//找到一个子窗口(视图)设置为活动视

              }

       }

 

       if (bMakeVisible)

       {

              // send initial update to all views (and other controls) in the frame

              SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); //发出WM_INITIALUPDATE消息,调用OnInitialUpdate()。

              // give view a chance to save the focus (CFormView needs this)

              if (pView != NULL)

                     pView->OnActivateFrame(WA_INACTIVE, this);//该函数为纯虚函数,可重载

 

              // finally, activate the frame

              // (send the default show command unless the main desktop window)

              int nCmdShow = -1;      // default

              CWinApp* pApp = AfxGetApp();

              if (pApp != NULL && pApp->m_pMainWnd == this)//仅对单文档有效!因为只有单文档的m_pMainWnd才会调用InitialUpdateFrame,多文档是新创建的ChildFrm调用

              {

                     nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain

                     pApp->m_nCmdShow = -1; // set to default after first time将m_nCmdShow重置为 -1

//int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 _In_ LPTSTR lpCmdLine, int nCmdShow)//入口,nCmdShow = SW_SHOWNORMAL = 1

{

...

if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

...

}

BOOL AFXAPI AfxWinInit(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance,
 _In_z_ LPTSTR lpCmdLine, _In_ int nCmdShow)//初始化

{

...

 CWinApp* pApp = AfxGetApp();
 if (pApp != NULL)
 {
  // Windows specific initialization (not done if no CWinApp)
  pApp->m_hInstance = hInstance;
  hPrevInstance; // Obsolete.
  pApp->m_lpCmdLine = lpCmdLine;
  pApp->m_nCmdShow = nCmdShow;//所以程序初始化时,m_nCmdShow = 1
  pApp->SetCurrentHandles();
 }

...

}

              }

              ActivateFrame(nCmdShow);

//对于单文档,第一次运行到这里时(新建或者打开文档,单文档不能修改cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing,因为单文档的m_pMainWnd是在CDocTemplate::OpenDocumentFile()里动态创建的,而多文档的m_pMainWnd是之前就创建好的),nCmdShow = m_nCmdShow,而m_nCmdShow被修改为-1(由于该值不能被传入ShowWindow(),所以在之后的CXXXApp::InitialInstance()中为m_pMainWnd->ShowWindow(SW_SHOW)而不是m_pMainWnd->ShowWindow(m_nCmdShow)),而之后在程序运行过程中,若窗口状态等发生变化,m_nCmdShow会发生变化,具体原理存疑。而后第二次运行到这里nCmdShow = m_nCmdShow

//对于多文档,第一次运行到这里时,nCmdShow = -1

              if (pView != NULL)

                     pView->OnActivateView(TRUE, pView, pView);//使该视图成为活动视,可重载

       }

 

       // update frame counts and frame title (may already have been visible)

       if (pDoc != NULL)

              pDoc->UpdateFrameCounts();

       OnUpdateFrameTitle(TRUE);

}

void
CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify)
{
#ifdef _DEBUG
       if (pViewNew != NULL)
       {
              ASSERT(IsChild(pViewNew));
              ASSERT_KINDOF(CView, pViewNew);
       }
#endif //_DEBUG

       CView* pViewOld = m_pViewActive;
       if (pViewNew == pViewOld)
              return;     // do not re-activate if SetActiveView called more than once

       m_pViewActive = NULL;   // no active for the following processing

       // deactivate the old one
       if (pViewOld != NULL)//对于多文档,则为NULL
              pViewOld->OnActivateView(FALSE, pViewNew, pViewOld);

       // if the OnActivateView moves the active window,
       //    that will veto this change
       if (m_pViewActive != NULL)
              return;     // already set
       m_pViewActive = pViewNew;

       // activate
       if (pViewNew != NULL && bNotify)//是否通知?通知则调用
              pViewNew->
OnActivateView(TRUE, pViewNew, pViewOld);
}

 

 

void CChildFrame::ActivateFrame(int nCmdShow)//nCmdShow默认为-1
{
       // TODO: 在此添加专用代码和/或调用基类
       //nCmdShow = SW_SHOWMAXIMIZED;//通过修改nCmdShow来修改子框架窗口风格

       CMDIChildWnd::ActivateFrame(nCmdShow);
}

void CMDIChildWnd::ActivateFrame(int nCmdShow)
{
       BOOL bVisibleThen = (GetStyle() & WS_VISIBLE) != 0;
       CMDIFrameWnd* pFrameWnd = GetMDIFrame();
       ASSERT_VALID(pFrameWnd);

       // determine default show command
       if (nCmdShow == -1)
       {
              // get maximized state of frame window (previously active child)
              BOOL bMaximized;
              pFrameWnd->MDIGetActive(&bMaximized);

              // convert show command based on current style
              DWORD dwStyle = GetStyle();
              if (bMaximized || (dwStyle & WS_MAXIMIZE))
                     nCmdShow = SW_SHOWMAXIMIZED;
              else if (dwStyle & WS_MINIMIZE)
                     nCmdShow = SW_SHOWMINIMIZED;
       }

       // finally, show the window
       CFrameWnd::ActivateFrame(nCmdShow);

       // update the Window menu to reflect new child window
       CMDIFrameWnd* pFrame = GetMDIFrame();
       ::SendMessage(pFrame->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);

       // Note: Update the m_bPseudoInactive flag.  This is used to handle the
       //  last MDI child getting hidden.  Windows provides no way to deactivate
       //  an MDI child window.

       BOOL bVisibleNow = (GetStyle() & WS_VISIBLE) != 0;
       if (bVisibleNow == bVisibleThen)
              return;

       if (!bVisibleNow)
       {
              // get current active window according to Windows MDI
              HWND hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
                     WM_MDIGETACTIVE, 0, 0);
              if (hWnd != m_hWnd)
              {
                     // not active any more -- window must have been deactivated
                     ASSERT(!m_bPseudoInactive);
                     return;
              }

              // check next window
              ASSERT(hWnd != NULL);
              pFrameWnd->MDINext();

              // see if it has been deactivated now...
              hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
                     WM_MDIGETACTIVE, 0, 0);
              if (hWnd == m_hWnd)
              {
                     // still active -- fake deactivate it
                     ASSERT(hWnd != NULL);
                    
OnMDIActivate(FALSE, NULL, this);
                     m_bPseudoInactive = TRUE;   // so MDIGetActive returns NULL
              }
       }
       else if (m_bPseudoInactive)
       {
              // if state transitioned from not visible to visible, but
              //  was pseudo deactivated -- send activate notify now
             
OnMDIActivate(TRUE, this, NULL);
              ASSERT(!m_bPseudoInactive); // should get set in OnMDIActivate!
       }
}

void CFrameWnd::ActivateFrame(int nCmdShow)
       // nCmdShow is the normal show mode this frame should be in
{
       // translate default nCmdShow (-1)
       if (nCmdShow == -1)
       {
              if (!IsWindowVisible())
                     nCmdShow = SW_SHOWNORMAL;
              else if (IsIconic())
                     nCmdShow = SW_RESTORE;
       }

       // bring to top before showing
       BringToTop(nCmdShow);

       if (nCmdShow != -1)
       {
              // show the window as specified
              ShowWindow(nCmdShow);//所以对于单文档,在CXXXApp::InitialInstance里m_pMainWnd->ShowWindow(SW_SHOW)之前,已经调用过一次ShowWindow,只不过没有UpdateWindow(),所以还是以m_pMainWnd->ShowWindow为准。

//对于多文档,此处的ShowWindow乃是子窗口框架的ShowWindow,主框架窗口的ShowWindow在CXXXApp::InitialInstance里的pMainFrame->ShowWindow(m_nCmdShow)

              // and finally, bring to top after showing
              BringToTop(nCmdShow);
       }
}

 

void CMDIChildWnd::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd*)
{
       m_bPseudoInactive = FALSE;  // must be happening for real

       // make sure MDI client window has correct client edge
       UpdateClientEdge();

       // send deactivate notification to active view
       CView* pActiveView = GetActiveView();
       if (!bActivate && pActiveView != NULL)
              pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);

       // allow hook to short circuit normal activation
       BOOL bHooked = FALSE;
#ifndef _AFX_NO_OLE_SUPPORT
       if (m_pNotifyHook != NULL && m_pNotifyHook->OnDocActivate(bActivate))
              bHooked = TRUE;
#endif

       // update titles (don't AddToTitle if deactivate last)
       if (!bHooked)
              OnUpdateFrameTitle(bActivate || (pActivateWnd != NULL));

       // re-activate the appropriate view
       if (bActivate)
       {
              if (pActiveView != NULL && GetMDIFrame() == GetActiveWindow())
                     pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
       }

       // update menus
       if (!bHooked)
       {
             
OnUpdateFrameMenu(bActivate, pActivateWnd, NULL);
              GetMDIFrame()->DrawMenuBar();
       }
}

 

void CView::OnActivateView(BOOL bActivate, CView* pActivateView, CView*)//当一个视图成为活动视时,调用该函数。
{
       UNUSED(pActivateView);   // unused in release builds

       if (bActivate)
       {
              ASSERT(pActivateView == this);

              // take the focus if this frame/view/pane is now active
              if (IsTopParentActive())
                     SetFocus();
       }
}

 

 

 

posted @ 2013-10-18 15:04  陳さん様  阅读(659)  评论(0)    收藏  举报