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"); |
最後,類CFormView和CRecordView不調用函數PreCreateWindow。
來源:http://fafeng.blogbus.com/logs/22802679.html