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