PreCreateWindow

MFC9.0中

wincore.cpp中實現的函數AfxEndDeferRegisterClass自動預註冊3個窗口類,分別爲_afxWnd,_afxWndOleControl和_afxWndControlBar。自MFC 4.0起,類AfxWnd, AfxFrameOrView, AfxMDIFrame和AfxControlBar不再預註冊,見KB 140596

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

{

...

      // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go

      if (fToRegister & AFX_WND_REG)

      {

           // Child windows - no brush, no icon, safest default class styles

           wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

           wndcls.lpszClassName = _afxWnd;

           if (AfxRegisterClass(&wndcls))

                 fRegisteredClasses |= AFX_WND_REG;

      }

      if (fToRegister & AFX_WNDOLECONTROL_REG)

      {

           // OLE Control windows - use parent DC for speed

           wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

           wndcls.lpszClassName = _afxWndOleControl;

           if (AfxRegisterClass(&wndcls))

                 fRegisteredClasses |= AFX_WNDOLECONTROL_REG;

      }

      if (fToRegister & AFX_WNDCONTROLBAR_REG)

      {

           // Control bar windows

           wndcls.style = 0;   // control bars don't handle double click

           wndcls.lpszClassName = _afxWndControlBar;

           wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

           if (AfxRegisterClass(&wndcls))

                 fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;

      }

      if (fToRegister & AFX_WNDMDIFRAME_REG)

      {

           // MDI Frame window (also used for splitter window)

           wndcls.style = CS_DBLCLKS;

           wndcls.hbrBackground = NULL;

           if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))

                 fRegisteredClasses |= AFX_WNDMDIFRAME_REG;

      }

      if (fToRegister & AFX_WNDFRAMEORVIEW_REG)

      {

           // SDI Frame or MDI Child windows or views - normal colors

           wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

           wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

           if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))

                 fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;

      }

      if (fToRegister & AFX_WNDCOMMCTLS_REG)

      {

           // this flag is compatible with the old InitCommonControls() API

           init.dwICC = ICC_WIN95_CLASSES;

           fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);

           fToRegister &= ~AFX_WIN95CTLS_MASK;

      }

      if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)

      {

           init.dwICC = ICC_UPDOWN_CLASS;

           fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);

      }

      if (fToRegister & AFX_WNDCOMMCTL_PAGER_REG)

      {

           init.dwICC = ICC_PAGESCROLLER_CLASS;

           fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PAGER_REG);

      }

...

}

 

之後進入AfxDeferRegisterClass,再進入實現在MainFrm.cpp中(這是由於CMainFrame中重寫了PreCreateWindow)的函數CMainFrame::PreCreateWindow

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

      if( !CFrameWnd::PreCreateWindow(cs) ① )

           return FALSE;

      // TODO: Modify the Window class or styles here by modifying

      //  the CREATESTRUCT cs

 

      return TRUE;

}

①處調用winfrm.cpp中的函數PreCreateWindow

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

      if (cs.lpszClass == NULL)

      {

           VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

           cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background

      }

 

      if (cs.style & FWS_ADDTOTITLE)

           cs.style |= FWS_PREFIXTITLE;

 

      cs.dwExStyle |= WS_EX_CLIENTEDGE;

 

      return TRUE;

}

其中函數AfxDeferRegisterClass定義在afximpl.h中

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

以上完成了註冊窗口過程。

 

再轉入實現在winfrm.cpp中的函數CFrameWnd::Create

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

      LPCTSTR lpszWindowName,

      DWORD dwStyle,

      const RECT& rect,

      CWnd* pParentWnd,

      LPCTSTR lpszMenuName,

      DWORD dwExStyle,

      CCreateContext* pContext)

{

      HMENU hMenu = NULL;

      if (lpszMenuName != NULL)

      {

           // load in a menu that will get destroyed when window gets destroyed

      if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

           rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

           pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

      {…}

 

      return TRUE;

}

它調用了實現在wincore.cpp中的函數CWnd::CreateEx創建窗口

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

      LPCTSTR lpszWindowName, DWORD dwStyle,

      int x, int y, int nWidth, int nHeight,

      HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

      if (!PreCreateWindow(cs) ②)

      {

           PostNcDestroy();

           return FALSE;

      }

 

      AfxHookWindowCreate(this);

}

②處爲函數CMainFrame::PreCreateWindow。

 

綜上流程,CMainFrame::PreCreateWindow分別在註冊和創建窗口時被2次調用。搜尋MFC調用順序可以調試(Debug)應用程序,把Step Into(F11),Step Over(F10)和斷點(Breakpoint)結合使用,效果最佳!

 

由於定義在afxwin.h中的函數是虛函數

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

因而可以在自己程序定義的CMainFrame中重寫(Override)它,在該函數的第一行加入調試(Debug)中的事件紀錄,TRACE/TRACE0/TRACE1/TRACE2/TRACE3,非MFC程序則需要用Win32格式化調試輸出

TRACE(L"CMainFrame::PreCreateWindow \n");

這樣就能在調試(Debug)中看到此輸出(output)信息,可以看到它輸出了兩次,這從另一方面再次驗證了上述結論,由於C++多態性,派生類中重寫虛函數,若對象是派生類則調用派生類的函數。若再在程序的View類(如類CxxxView,xxx爲項目名)中重寫此方法,在該函數的第一行加上

TRACE(L"CtestView::PreCreateWindow \n");

可以看到,此輸出接在CMainFrame的兩次輸出後僅輸出一次。

 

最後,類CFormView和CRecordView不調用函數PreCreateWindow。



來源:http://fafeng.blogbus.com/logs/22802679.html


發佈了16 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章