MFC 流程跟踪(窗口设计,注册,创建)

MFC的流程跟踪

(窗口的设计,注册,创建)

跟踪MFC的程序流程,我们一步一步来,不要怕麻烦!

1       首先是MFC的入口函数:

extern "C"int WINAPI

_tWinMain(HINSTANCEhInstance, HINSTANCE hPrevInstance,

         _In_ LPTSTR lpCmdLine, int nCmdShow)

#pragma warning(suppress:4985)

{

         // callshared/exported WinMain

         returnAfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

2       然后进入AfxWinMain(hInstance, hPrevInstance, lpCmdLine,nCmdShow);

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCEhPrevInstance,

         _In_ LPTSTR lpCmdLine, int nCmdShow)

{

         ASSERT(hPrevInstance == NULL);

        

         // pThreadpApp都是指向the App全局对象,不过这两个指针都是the App的父类指针

         intnReturnCode = -1;

         CWinThread* pThread = AfxGetThread();

         CWinApp* pApp = AfxGetApp();

 

         // 这个是完成MFC的初始化

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

                   gotoInitFailure;

 

         // 应用程序全局初始化,主要是文档相关

         if(pApp != NULL && !pApp->InitApplication())

                   gotoInitFailure;

 

         // 调用子类的Instance函数来实现初始化,这个是重点,窗口的设计

         // 注册,创建都在这个函数里面了,中间会调用很多函数

         if(!pThread->InitInstance())

         {

                   if(pThread->m_pMainWnd != NULL)

                   {

                            TRACE(traceAppMsg,0, "Warning: Destroying non-NULLm_pMainWnd\n");

                            pThread->m_pMainWnd->DestroyWindow();

                   }

                   nReturnCode =pThread->ExitInstance();

                   gotoInitFailure;

         }

         // 消息循环

         nReturnCode = pThread->Run();

 

InitFailure:

#ifdef _DEBUG

         // Check formissing AfxLockTempMap calls

         if(AfxGetModuleThreadState()->m_nTempMapLock != 0)

         {

                   TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero(%ld).\n",

                            AfxGetModuleThreadState()->m_nTempMapLock);

         }

         AfxLockTempMaps();

         AfxUnlockTempMaps(-1);

#endif

 

         AfxWinTerm();

         returnnReturnCode;

}

 

2.1 接下来进入AfxWinInit看看

BOOL AFXAPIAfxWinInit(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,

         _In_z_ LPTSTR lpCmdLine, _In_ int nCmdShow)

{

         ASSERT(hPrevInstance == NULL);

 

 

         // handlecritical errors and avoid Windows message boxes

         SetErrorMode(SetErrorMode(0) |

                   SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

 

         // setresource handles

         AFX_MODULE_STATE* pModuleState =AfxGetModuleState();

         pModuleState->m_hCurrentInstanceHandle= hInstance;

         pModuleState->m_hCurrentResourceHandle= hInstance;

         pModuleState->CreateActivationContext();

 

         // fill inthe initial state for the application

         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;

                   pApp->SetCurrentHandles();

         }

 

         // initializethread specific data (for main thread)

         if(!afxContextIsDLL)

                   AfxInitThread();

 

         returnTRUE;

}

 

这个函数主要就是完成MFC的初始化,也不需要多解释。其实如果我在控制台程序创建时,勾选了MFC的库,那么在_tmain函数中也会出现这样一个东西,如下:

int _tmain(int argc,TCHAR* argv[], TCHAR* envp[])

{

         int nRetCode = 0;

 

         HMODULE hModule =::GetModuleHandle(NULL);

 

         if (hModule != NULL)

         {

                   // 初始化 MFC 并在失败时显示错误

                   if (!AfxWinInit(hModule,NULL, ::GetCommandLine(), 0))

                   {

                            // TODO: 更改错误代码以符合您的需要

                            _tprintf(_T("错误: MFC 初始化失败\n"));

                            nRetCode = 1;

                   }

                   else

                   {

                            // TODO: 在此处为应用程序的行为编写代码。

                   }

         }

         else

         {

                   // TODO: 更改错误代码以符合您的需要

                   _tprintf(_T("错误: GetModuleHandle 失败\n"));

                   nRetCode = 1;

         }

 

         return nRetCode;

}

2.2    再看看BOOLCWinApp::InitApplication()

BOOLCWinApp::InitApplication()

{

         if (CDocManager::pStaticDocManager !=NULL)

         {

                   if (m_pDocManager == NULL)

                            m_pDocManager =CDocManager::pStaticDocManager;

                   CDocManager::pStaticDocManager= NULL;

         }

 

         if (m_pDocManager != NULL)

                   m_pDocManager->AddDocTemplate(NULL);

         else

                   CDocManager::bStaticInit =FALSE;

 

         LoadSysPolicies();

 

         return TRUE;

}

这个函数主要就是管理文档的,对目前跟踪流程也没多大用处,先不管它

2.3    接下来再进入我们最关心的函数Instance看看,就是在这个函数中我们进行了窗口的设计,注册,创建,让我们一步一步地揭开它神秘的面纱吧。

BOOL Cmfc4StdApp::InitInstance()

{

         InitCtrls.dwSize = sizeof(InitCtrls);

         InitCtrls.dwICC = ICC_WIN95_CLASSES;

         InitCommonControlsEx(&InitCtrls);

         CWinAppEx::InitInstance();

 

         if(!AfxOleInit())

         {

                   AfxMessageBox(IDP_OLE_INIT_FAILED);

                   returnFALSE;

         }

 

         AfxEnableControlContainer();

         EnableTaskbarInteraction(FALSE);

         SetRegistryKey(_T(应用程序向导生成的本地应用程序));

         LoadStdProfileSettings(4);  // 加载标准的INI文件

 

         InitContextMenuManager();

 

         InitKeyboardManager();

 

         InitTooltipManager();

         CMFCToolTipInfo ttParams;

         ttParams.m_bVislManagerTheme = TRUE;

         theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,

                   RUNTIME_CLASS(CMFCToolTipCtrl),&ttParams);

 

         // 注册应用程序的文档模板,文档模板将用作文档,框架,视口之间的连接

         CSingleDocTemplate* pDocTemplate;

         pDocTemplate = newCSingleDocTemplate(

                   IDR_MAINFRAME,

                   RUNTIME_CLASS(Cmfc4StdDoc),

                   RUNTIME_CLASS(CMainFrame),       // SDI框架

                   RUNTIME_CLASS(Cmfc4StdView));

         if(!pDocTemplate)

                   returnFALSE;

         AddDocTemplate(pDocTemplate);

 

         // 分析标准shell命令,DDE,并打开文件操作

         CCommandLineInfo cmdInfo;

         ParseCommandLine(cmdInfo);

 

         // 调度在命令行中指定的命令,如果用/RegServer/Register/Unregserver /Unregister

         // 启动应用程序,则返回false;所有的秘密都在这个函数里了

         if(!ProcessShellCommand(cmdInfo))

                   returnFALSE;

 

         //唯一的一个主窗口已经初始化,因此显示它并对其进行更新

         m_pMainWnd->ShowWindow(SW_SHOW);

         m_pMainWnd->UpdateWindow();

         //仅当有后缀时才调用DragAcceptFiles,在SDI应用程序中,这应该在ProcessShellCommand之后

         returnTRUE;

}

2.3.1 我们进入ProcessShellCommand看看

BOOLCWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)

{

         BOOL bResult = TRUE;

         switch(rCmdInfo.m_nShellCommand)

         {

         caseCCommandLineInfo::RestartByRestartManager://为了方便,删除了执行语句

         case CCommandLineInfo::FileNew:

                   if(!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))

                            OnFileNew();

                   if(m_pMainWnd == NULL)

                            bResult= FALSE;

                   break;

         caseCCommandLineInfo::FileOpen:                //为了方便,删除了执行语句

         caseCCommandLineInfo::FilePrintTo:   //为了方便,删除了执行语句

         caseCCommandLineInfo::FilePrint:                  //为了方便,删除了执行语句

         caseCCommandLineInfo::FileDDENoShow:  //为了方便,删除了执行语句

         caseCCommandLineInfo::FileDDE:                           //为了方便,删除了执行语句

         caseCCommandLineInfo::AppRegister:          //为了方便,删除了执行语句

         caseCCommandLineInfo::AppUnregister:                //为了方便,删除了执行语句

         }

         returnbResult;

}

可以看出,这个函数就是处理各种命令的函数,我们的程序在这里会跳到用特殊颜色标记的地方执行,我们可以看一看,接下来进入的就是OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))

2.3.1.1 进入函数BOOL CCmdTarget::OnCmdMsg

BOOLCCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,

         AFX_CMDHANDLERINFO* pHandlerInfo)

{

//此处省略各种条件编译语句

#ifdef _DEBUG

                            if (nCode == CN_COMMAND)

                                     TRACE(traceCmdRouting,1, "SENDING command id 0x%04X to %hstarget.\n", nID,

                                               GetRuntimeClass()->m_lpszClassName);

                            else if (nCode >CN_COMMAND)

                                     TRACE(traceCmdRouting,1, "SENDING control notification %d fromcontrol id 0x%04X to %hs window.\n", nCode, nID,GetRuntimeClass()->m_lpszClassName);

#endif //_DEBUG

                            return _AfxDispatchCmdMsg(this, nID, nCode,

                                     lpEntry->pfn,pExtra, lpEntry->nSig, pHandlerInfo);

                   }

         }

         returnFALSE;   // nothandled

}

主框架调用这个函数来分发命令消息,或者处理用户接口的更新命令,程序会在这个函数中进入AfxDisPatchCmdMsg中,那我们就进到里面探探。

2.3.1.1.1

AFX_STATIC BOOLAFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode, AFX_PMSG pfn, void*pExtra, UINT_PTR nSig, AFX_CMDHANDLERINFO* pHandlerInfo)

AFX_STATIC BOOLAFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode,

         AFX_PMSG pfn, void*pExtra, UINT_PTR nSig, AFX_CMDHANDLERINFO* pHandlerInfo)

                   //return TRUE to stop routing

{

         ENSURE_VALID(pTarget);

         UNUSED(nCode);   // unused inrelease builds

 

         unionMessageMapFunctions mmf;

         mmf.pfn = pfn;

         BOOL bResult = TRUE; // default is ok

 

         if(pHandlerInfo != NULL)

         {

                   //just fill in the information, don't do it

                   pHandlerInfo->pTarget =pTarget;

                   pHandlerInfo->pmf =mmf.pfn;

                   returnTRUE;

         }

 

         switch(nSig)

         {

                   caseAfxSigCmd_v:

                   //normal command or control notification

                   ASSERT(CN_COMMAND == 0);        // CN_COMMANDsame as BN_CLICKED

                   ASSERT(pExtra == NULL);

                   (pTarget->*mmf.pfnCmd_v_v)();

                   break;

}

         returnbResult;

}

这个也是消息相关的函数,程序会进入特殊颜色标记的部分,那我们就进去看一看

2.3.1.1.1.a

void CWinApp::OnFileNew()

{

         if(m_pDocManager != NULL)

                   m_pDocManager->OnFileNew();

}

此时程序进入了OnFileNew()函数,我们继续跟踪进入看看:

2.3.1.1.1.b

void CDocManager::OnFileNew()

{

         if(m_templateList.IsEmpty())

         {

                   TRACE(traceAppMsg, 0, "Error: no document templates registered withCWinApp.\n");

                   AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);

                   return;

         }

 

         // 获取第一个文档模板,对于单文档只有一个文档模板

         CDocTemplate* pTemplate =(CDocTemplate*)m_templateList.GetHead();

         if(m_templateList.GetCount() > 1)

         {

                   //more than one document template to choose from

                   //bring up dialog prompting user

                   CNewTypeDlgdlg(&m_templateList);

                   INT_PTR nID = dlg.DoModal();

                   if(nID == IDOK)

                            pTemplate =dlg.m_pSelectedTemplate;

                   else

                            return;     // none - cancel operation

         }

 

         ASSERT(pTemplate != NULL);

         ASSERT_KINDOF(CDocTemplate, pTemplate);

 

         pTemplate->OpenDocumentFile(NULL);

                   //if returns NULL, the user has already been alerted

}

函数会调试至此进入特殊颜色标记部分,进入继续看看

2.3.1.1.1.c

CDocument*CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)

{

         return OpenDocumentFile(lpszPathName,TRUE, bMakeVisible);

}

2.3.1.1.1.d

CDocument*CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bAddToMRU, BOOLbMakeVisible)

{

         CDocument* pDocument = NULL;

         CFrameWnd* pFrame = NULL;

         BOOL bCreated = FALSE;      // => docand frame created

         BOOL bWasModified = FALSE;

 

         if(m_pOnlyDoc != NULL)

         {

                   //already have a document - reinit it

                   pDocument = m_pOnlyDoc;

                   if(!pDocument->SaveModified())

                   {

                            // set a flag to indicate that the document being openedshould not

                            // be removed from the MRU list, if it was being openedfrom there

                            g_bRemoveFromMRU =FALSE;

                            return NULL;       // leave the original one

                   }

 

                   pFrame =(CFrameWnd*)AfxGetMainWnd();

                   ASSERT(pFrame != NULL);

                   ASSERT_KINDOF(CFrameWnd,pFrame);

                   ASSERT_VALID(pFrame);

         }

         else

         {

                   //create a new document

                   pDocument = CreateNewDocument();

                   ASSERT(pFrame == NULL);     // will becreated below

                   bCreated = TRUE;

         }

 

         if(pDocument == NULL)

         {

                   AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);

                   returnNULL;

         }

         ASSERT(pDocument == m_pOnlyDoc);

 

         if(pFrame == NULL)

         {

                   ASSERT(bCreated);

 

                   //create frame - set as main document frame

                   BOOL bAutoDelete =pDocument->m_bAutoDelete;

                   pDocument->m_bAutoDelete =FALSE;

                                               // don't destroy if something goes wrong

                   pFrame = CreateNewFrame(pDocument, NULL);

                   pDocument->m_bAutoDelete =bAutoDelete;

                   if(pFrame == NULL)

                   {

                            AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);

                            delete pDocument;       // explicitdelete on error

                            return NULL;

                   }

         }

 

         if(lpszPathName == NULL)

         {

                   //create a new document

                   SetDefaultTitle(pDocument);

 

                   //avoid creating temporary compound file when starting up invisible

                   if(!bMakeVisible)

                            pDocument->m_bEmbedded= TRUE;

 

                   if(!pDocument->OnNewDocument())

                   {

                            // user has been alerted to what failed in OnNewDocument

                            TRACE(traceAppMsg,0, "CDocument::OnNewDocument returnedFALSE.\n");

                            if (bCreated)

                                     pFrame->DestroyWindow();    // will destroydocument

                            return NULL;

                   }

         }

         else

         {

                   CWaitCursor wait;

 

                   //open an existing document

                   bWasModified =pDocument->IsModified();

                   pDocument->SetModifiedFlag(FALSE);  // not dirty foropen

 

                   if(!pDocument->OnOpenDocument(lpszPathName))

                   {

                            // user has been alerted to what failed in OnOpenDocument

                            TRACE(traceAppMsg,0, "CDocument::OnOpenDocument returnedFALSE.\n");

                            if (bCreated)

                            {

                                     pFrame->DestroyWindow();    // will destroy document

                            }

                            else if(!pDocument->IsModified())

                            {

                                     // original document is untouched

                                     pDocument->SetModifiedFlag(bWasModified);

                            }

                            else

                            {

                                     // we corrupted the original document

                                     SetDefaultTitle(pDocument);

 

                                     if (!pDocument->OnNewDocument())

                                     {

                                               TRACE(traceAppMsg,0, "Error: OnNewDocument failed after trying"

                                                        "to open a document - trying to continue.\n");

                                               // assume we can continue

                                     }

                            }

                            return NULL;       // open failed

                   }

                   pDocument->SetPathName(lpszPathName,bAddToMRU);

                   pDocument->OnDocumentEvent(CDocument::onAfterOpenDocument);

         }

 

         CWinThread* pThread = AfxGetThread();

         ASSERT(pThread);

         if(bCreated && pThread->m_pMainWnd == NULL)

         {

                   //set as main frame (InitialUpdateFrame will show the window)

                   pThread->m_pMainWnd =pFrame;

         }

         InitialUpdateFrame(pFrame, pDocument,bMakeVisible);

 

         returnpDocument;

}

(1)pDocument =CreateNewDocument()

CDocument*CDocTemplate::CreateNewDocument()

{

         // defaultimplementation constructs one from CRuntimeClass

         if(m_pDocClass == NULL)

         {

                   TRACE(traceAppMsg, 0, "Error: you must overrideCDocTemplate::CreateNewDocument.\n");

                   ASSERT(FALSE);

                   returnNULL;

         }

         //创建一个新的文档文档对象,是RUNTIME_CLASS(CFirstDoc)中的对象

         CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();

         if(pDocument == NULL)

         {

                   TRACE(traceAppMsg, 0, "Warning: Dynamic create of document type %hsfailed.\n",

                            m_pDocClass->m_lpszClassName);

                   returnNULL;

         }

         ASSERT_KINDOF(CDocument, pDocument);

         AddDocument(pDocument);

         returnpDocument;

}

(2)CFrameWnd*CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)

{

         if(pDoc != NULL)

                   ASSERT_VALID(pDoc);

         // create aframe wired to the specified document

 

         ASSERT(m_nIDResource != 0); // must have a resource ID to load from

         CCreateContext context;

         context.m_pCurrentFrame = pOther;

         context.m_pCurrentDoc = pDoc;

         context.m_pNewViewClass = m_pViewClass;

         context.m_pNewDocTemplate = this;

 

         if(m_pFrameClass == NULL)

         {

                   TRACE(traceAppMsg, 0, "Error: you must override CDocTemplate::CreateNewFrame.\n");

                   ASSERT(FALSE);

                   returnNULL;

         }

         // 创建一个运行时的框架对象

         CFrameWnd* pFrame =(CFrameWnd*)m_pFrameClass->CreateObject();

         if(pFrame == NULL)

         {

                   TRACE(traceAppMsg, 0, "Warning: Dynamic create of frame %hsfailed.\n",

                            m_pFrameClass->m_lpszClassName);

                   returnNULL;

         }

         ASSERT_KINDOF(CFrameWnd, pFrame);

 

         if(context.m_pNewViewClass == NULL)

                   TRACE(traceAppMsg, 0, "Warning: creating frame with no defaultview.\n");

 

         // create newfrom resource

         if (!pFrame->LoadFrame(m_nIDResource,

                            WS_OVERLAPPEDWINDOW| FWS_ADDTOTITLE,   // default frame styles

                            NULL,&context))

         {

                   TRACE(traceAppMsg, 0, "Warning: CDocTemplate couldn't create aframe.\n");

                   //frame will be deleted in PostNcDestroy cleanup

                   returnNULL;

         }

 

         // it worked!

         returnpFrame;

}

(2)_1

BOOLCMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd,CCreateContext* pContext)

(2)_11

BOOLCFrameWndEx::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd*pParentWnd, CCreateContext* pContext)

{

         m_Impl.m_nIDDefaultResource =nIDResource;

         m_Impl.LoadLargeIconsState();

 

         if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,pParentWnd, pContext))

         {

                   returnFALSE;

         }

 

         m_Impl.OnLoadFrame();

         returnTRUE;

}

(2)_111

BOOLCFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,

         CWnd* pParentWnd, CCreateContext*pContext)

{

         // only dothis once

         ASSERT_VALID_IDR(nIDResource);

         ASSERT(m_nIDHelp == 0 || m_nIDHelp ==nIDResource);

 

         m_nIDHelp = nIDResource;    // ID for helpcontext (+HID_BASE_RESOURCE)

 

         CString strFullString;

         if(strFullString.LoadString(nIDResource))

                   AfxExtractSubString(m_strTitle,strFullString, 0);    // first sub-string

 

         VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

 

         // attempt tocreate the window

         LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle,nIDResource);

         CString strTitle = m_strTitle;

         if (!Create(lpszClass, strTitle,dwDefaultStyle, rectDefault,

           pParentWnd, ATL_MAKEINTRESOURCE(nIDResource),0L, pContext))

         {

                   returnFALSE;   //will self destruct on failure normally

         }

 

         // save thedefault menu handle

         ASSERT(m_hWnd != NULL);

         m_hMenuDefault = m_dwMenuBarState ==AFX_MBS_VISIBLE ? ::GetMenu(m_hWnd) : m_hMenu;

 

         // loadaccelerator resource

         LoadAccelTable(ATL_MAKEINTRESOURCE(nIDResource));

 

         if(pContext == NULL)   // send initial update

                   SendMessageToDescendants(WM_INITIALUPDATE,0, 0, TRUE, TRUE);

 

         returnTRUE;

}

跳了半天,真够麻烦的,不过好的是我们终于看到了绿洲了,上面特殊颜色标记的东西不就是迹象吗,所以我们继续搞下去,坚持到底就是光明!

(2)_111x  AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)

BOOL AFXAPIAfxEndDeferRegisterClass(LONG fToRegister)

{

         // mask offall classes that are already registered

         AFX_MODULE_STATE* pModuleState =AfxGetModuleState();

         fToRegister &=~pModuleState->m_fRegisteredClasses;

         if(fToRegister == 0)

                   returnTRUE;

 

         LONG fRegisteredClasses = 0;

 

         // commoninitialization

         WNDCLASS wndcls;

         memset(&wndcls,0, sizeof(WNDCLASS));   // start with NULLdefaults

         wndcls.lpfnWndProc= DefWindowProc;

         wndcls.hInstance= AfxGetInstanceHandle();

         wndcls.hCursor= afxData.hcurArrow;

 

         INITCOMMONCONTROLSEX init;

         init.dwSize = sizeof(init);

//此处省略各种款式类型的窗口

         // work toregister classes as specified by fToRegister, populate fRegisteredClasses as wego

         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;

         }

//此处省略各种款式类型的窗口

         // save newstate of registered controls

         pModuleState->m_fRegisteredClasses|= fRegisteredClasses;

         // specialcase for all common controls registered, turn on AFX_WNDCOMMCTLS_REG

         if((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) ==AFX_WIN95CTLS_MASK)

         {

                   pModuleState->m_fRegisteredClasses|= AFX_WNDCOMMCTLS_REG;

                   fRegisteredClasses |=AFX_WNDCOMMCTLS_REG;

         }

 

         // must haveregistered at least as mamy classes as requested

         return(fToRegister & fRegisteredClasses) == fToRegister;

}

从特殊颜色标记的语句可以看出,在窗口注册函数中,其实包含着窗口类的设计,程序会在

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

                            fRegisteredClasses|= AFX_WNDFRAMEORVIEW_REG

中调用_AfxRegisterWithIcon函数,接下来我们再看看这个函数,做了些神马

(2)_111y

AFX_STATIC BOOLAFXAPI _AfxRegisterWithIcon(WNDCLASS* pWndCls,

         LPCTSTR lpszClassName, UINT nIDIcon)

{

         pWndCls->lpszClassName =lpszClassName;

         HINSTANCE hInst =AfxFindResourceHandle(

                   ATL_MAKEINTRESOURCE(nIDIcon),ATL_RT_GROUP_ICON);

         if((pWndCls->hIcon = ::LoadIconW(hInst, ATL_MAKEINTRESOURCEW(nIDIcon))) ==NULL)

         {

                   //use default icon

                   pWndCls->hIcon =::LoadIcon(NULL, IDI_APPLICATION);

         }

         return AfxRegisterClass(pWndCls);

}

我们可以看到,在这个函数中,继续完成窗口类的设计,包括光标,图标,以及窗口类名字的设置,在这些设置完后,函数返回了 AfxRegisterClass(pWndCls);

我们再跳进去看看,这个函数是做了些神马东西

(2)_111z

BOOL AFXAPIAfxRegisterClass(WNDCLASS* lpWndClass)

{

         WNDCLASS wndcls;                 

         if(AfxCtxGetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,

                   &wndcls))

         {

                   //class already registered

                   returnTRUE;

         }

 

         if (!::AfxCtxRegisterClass(lpWndClass))

         {

                   TRACE(traceAppMsg, 0, _T("Can't register window class named %s\n"),

                            lpWndClass->lpszClassName);

                   returnFALSE;

         }

 

         BOOL bRet = TRUE;

 

         if(afxContextIsDLL)

         {

                   AfxLockGlobals(CRIT_REGCLASSLIST);

                   TRY

                   {

                            // class registered successfully, add to registered list

                            AFX_MODULE_STATE*pModuleState = AfxGetModuleState();

                            pModuleState->m_strUnregisterList+=lpWndClass->lpszClassName;

                            pModuleState->m_strUnregisterList+='\n';

                   }

                   CATCH_ALL(e)

                   {

                            AfxUnlockGlobals(CRIT_REGCLASSLIST);

                            THROW_LAST();

                            // Note: DELETE_EXCEPTION not required.

                   }

                  END_CATCH_ALL

                   AfxUnlockGlobals(CRIT_REGCLASSLIST);

         }

 

         returnbRet;

}

我们继续调试程序到特殊颜色标记的地方,会进入下面的函数

(2)_111z1

AFX_ISOLATIONAWARE_STATICLINK_FUNC(ATOM,RegisterClassW,(constWNDCLASSW*lpWndClass),(lpWndClass),0)

止于此,我们终于看到了熟悉的函数RegisterClass了吧。我们再把设计和注册窗口的过程给捋一捋。

AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)

AfxEndDeferRegisterClass(LONGfToRegister)

AfxRegisterClass(pWndCls);

AfxCtxRegisterClass(lpWndClass)

AFX_ISOLATIONAWARE_STATICLINK_FUNC(ATOM,RegisterClassW,(constWNDCLASSW*lpWndClass),(lpWndClass),0)

仅仅一个设计和注册窗口就被搞了这么多步。

(2)_112

LPCTSTRCFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)

{

         ASSERT_VALID_IDR(nIDResource);

         HINSTANCE hInst =AfxFindResourceHandle(

                   ATL_MAKEINTRESOURCE(nIDResource),ATL_RT_GROUP_ICON);

         HICON hIcon = ::LoadIconW(hInst,ATL_MAKEINTRESOURCEW(nIDResource));

         if(hIcon != NULL)

         {

                   CREATESTRUCT cs;

                   memset(&cs, 0, sizeof(CREATESTRUCT));

                   cs.style = dwDefaultStyle;

                   PreCreateWindow(cs);

                            // will fill lpszClassName with default WNDCLASS name

                            // ignore instance handle from PreCreateWindow.

 

                   WNDCLASS wndcls;

                   if(cs.lpszClass != NULL &&

                            AfxCtxGetClassInfo(AfxGetInstanceHandle(),cs.lpszClass, &wndcls) &&

                            wndcls.hIcon !=hIcon)

                   {

                            // register a very similar WNDCLASS

                            return AfxRegisterWndClass(wndcls.style,

                                     wndcls.hCursor,wndcls.hbrBackground, hIcon);

                   }

         }

         returnNULL;        //just use the default

}

(2)_1121

BOOLCMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

         if( !CFrameWndEx::PreCreateWindow(cs))

                   returnFALSE;

         // TODO: ¨²ä?ä|ª¡§yT?

         //  CREATESTRUCT cs ¤¡äT?ä¡ã¨²¤¨¤¨°¨´º?

 

         returnTRUE;

}

(2) _1122

BOOLCFrameWndEx::PreCreateWindow(CREATESTRUCT& cs)

{

         m_dockManager.Create(this);

         m_Impl.SetDockingManager(&m_dockManager);

 

         m_Impl.RestorePosition(cs);

         return CFrameWnd::PreCreateWindow(cs);

}

(2) _1123

BOOLCFrameWnd::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;

 

         returnTRUE;

}

开始的时候我以为在这里又注册了一次窗口,这个问题令我蛋疼了好久,我不明白为什么要这么做,理由是什么。后来经过调用发现出现这样的函数并不代表一定要注册窗口,如果窗口已经注册了,就不会再继续注册了,MFC就是这样子,会在多个地方调用注册窗口程序,如果窗口类修改了,它就会真的去重新注册窗口,否则就不重新注册窗口。如:

BOOL AFXAPIAfxEndDeferRegisterClass(LONG fToRegister)

{

         // mask offall classes that are already registered

         AFX_MODULE_STATE* pModuleState =AfxGetModuleState();

         fToRegister &=~pModuleState->m_fRegisteredClasses;

         if(fToRegister == 0)  //fToRegister

                   returnTRUE;

….

}

BOOL AFXAPIAfxRegisterClass(WNDCLASS* lpWndClass)

{

         WNDCLASS wndcls;                 

         if(AfxCtxGetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,

                   &wndcls))

         {

                   //class already registered

                   returnTRUE;

         }

}

这里执行完毕就清楚了,其实这里的PreCreateWindow并没有重新注册窗口,因为我们并没有改变窗口类的内容。

 

在LPCTSTRCFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)

最后会调用这样一个函数:

if (cs.lpszClass != NULL &&

                            AfxCtxGetClassInfo(AfxGetInstanceHandle(),cs.lpszClass, &wndcls) &&

                            wndcls.hIcon !=hIcon)

                   {

                            // register a very similar WNDCLASS

                            return AfxRegisterWndClass(wndcls.style,

                                     wndcls.hCursor,wndcls.hbrBackground, hIcon);

                   }

这个函数还是真的执行了注册窗口的函数,至于微软说注册一个非常类似的窗口类,我还没有仔细考究。

所有这些都做完之后,就开始CreateWindow了

(2)_113    Create(lpszClass, strTitle, dwDefaultStyle,rectDefault,

          pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext)

窗口的创建就在这个Create函数里面了。

BOOLCFrameWnd::Create(LPCTSTR lpszClassName,

         LPCTSTR lpszWindowName,

         DWORD dwStyle,

         constRECT& rect,

         CWnd* pParentWnd,

         LPCTSTR lpszMenuName,

         DWORD dwExStyle,

         CCreateContext* pContext)

{…

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

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

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

         {

                   TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");

                   if(hMenu != NULL)

                            DestroyMenu(hMenu);

                   returnFALSE;

         }

 

}

(2)_1131

BOOLCWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

         LPCTSTR lpszWindowName, DWORD dwStyle,

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

         HWND hWndParent, HMENU nIDorHMenu,LPVOID lpParam)

到了这里基本上MFC的窗口设计,注册,创建的过程给弄完了。

但是MFC的消息映射机制还没有讲解,接下来去解析。

你可能感兴趣的:(创建,mfc,注册,流程跟踪,窗口设计)