读书人

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

发布时间: 2013-10-27 15:21:49 作者: rapoo

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);

// pThread,pApp都是指向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: 在¨2此??处?|通a?§过y修T改?

// CREATESTRUCT cs 来¤??修T改?窗???口¨2类¤¨¤或¨°样¨′式o?

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的消息映射机制还没有讲解,接下来去解析。

读书人网 >VC/MFC

热点推荐