MFC之代码跟踪

来源:互联网 发布:淘宝首页搜索 编辑:程序博客网 时间:2024/05/22 01:26

工程名为:StudyFrame

(1)  StudyFrame.cpp中CStudyFrame theApp; 这里声明了一个CWinApp的全局变量,因而会先进入到CWinApp的构造函数中。CStudyFrameApp类中定义了一个bool m_bHiColorIcons; 不知何用,在构造时赋成了true。回来后这个构造函数中只有一条语句m_bHiColorIcons =TRUE;暂不知何用。关键的来了,接下来会到哪里呢?我去,到了C运行时库了,这犀利了,我怎么跟踪。跳转(10)。

(2)  调用父类的构造函数,也就是CWinAppEx的构造函数,这个构造函数里仅仅是设置了一系列的初始值,没有另外生成对象,也没有调用别的什么函数。

(3)  CWinAppEx是CWinApp的子类,因而又调用CWinApp的构造函数,跳转(4)。回来后,设置了一系列的值,回到(1)。

(4)  CWinApp是CWinThread的子类,因而又调用CWinThread的构造函数,跳转(5)。回到CWinApp中,先给App赋名字CWinApp::CWinApp(LPCTSTRlpszAppName),是个带参数的构造函数。参数就是名字,当然可以是NULL。之后,调用全局函数AFX_MODULE_STATE*pModuleState = _AFX_CMDTARGET_GETSTATE();这又是一个什么结构体?反正是得到了一个状态对象。之后AFX_MODULE_THREAD_STATE*pThreadState =pModuleState->m_thread;这又是个什么结构体,得到了线程状态。pThreadState->m_pCurrentWinThread =this;线程状态的一个变量赋成了这个CWinApp。CWinApp的两个成员m_hThread = ::GetCurrentThread();m_nThreadID = ::GetCurrentThreadId();m_hThread,m_nThreadID是从CWinThread继承来的,代表了当前线程。又设置了一系列的值,包括一些定义为宏的函数。回到(3)。

(5)  CWinThread是CCmdTarget的子类,因而又调用CCmdTarget的构造函数,跳转(6)。回到CWinThread,这里面更没干什么事。赋了两个值m_pThreadParams =NULL; m_pfnThreadProc =NULL;然后调用了一个函数CWinThread::CommonConstruct();跳到(7)。这个构造函数就结束了,回到(4)。

(6)  CCmdTarget是CObject的子类,因而又调用CObject的构造函数(是个空构造函数)。至此到了类的顶层,开始一步步的往下调用各自的构造函数。调用CCmdTarget的构造函数。调用全局AfxGetModuleState(),返回一个AFX_MODULE_STATE值,不知何用,又很多的成员变量,可能跟程序状态环境有关。再设置一些成员变量,结束。回到(5)

(7)  CWinThread::CommonConstruct();从名字上看是通用创建的意思。m_pMainWnd =NULL; m_pActiveWnd =NULL;这里看到,CWinThread中有两个CWnd,一个叫做主窗口,另一个叫做激活窗口,并且声明为public的,子类继承下来应该会用到这两个窗口(是否由此,应用程序就和窗口关联起来了)。m_hThread =NULL; m_nThreadID = 0;将线程赋为空。猜赋为空是不科学的,因而在后面的某个地方肯定要以他们进行赋值,而这里只是初始化。调用全局函数_AFX_THREAD_STATE*pState =AfxGetThreadState();得到一个用于管理线程的对象,注意,在之后这个对象并没有赋给什么值。跳转(10).得到_AFX_THREAD_STATE后,又对pState这个线程状态进行了一些设置。回到(5)。

(8)  全局函数_AFX_THREAD_STATE*AFXAPIAfxGetThreadState()中先执行了此句_AFX_THREAD_STATE *pState =_afxThreadState.GetData();用另一种方式得到了线程状态,首先,这个_afxThreadState是哪里来的,这个函数是全局函数,那么这个对象一定是个全局对象。跟踪了一下发现有这么一句EXTERN_THREAD_LOCAL(_AFX_THREAD_STATE,_afxThreadState)。啥意思(连MSDN中都没有解释),又跟踪了一下,发现他是一个宏。#defineEXTERN_THREAD_LOCAL(class_name,ident_name) externCThreadLocal<class_name>ident_name;定义成了外部的CThreadLocal,显然,CThreadLocal是个模板,而ident_name是个对象,_AFX_THREAD_STATE是个类名。这样就解释通了。_afxThreadState是个模板类的对象,对象的类型是_AFX_THREAD_STATE。(MSDN中没有CThreadLocal这个类的解释,只能看源码)。先暂且看下GetData返回的是什么吧。跳到(11)。得到_AFX_THREAD_STATE后,ENSURE(pState != NULL); returnpState;把_AFX_THREAD_STATE返回了。回到(9)。

(9)  擦,好复杂,回头在说,反正是经过一系列的操作得到了_AFX_THREAD_STATE这个东西。回到(8)。

(10)这是个C运行库函数atexit(atonexit.c),应该是编译器加上的。没办法,跟吧。这个函数有个参数int__cdeclatexit (_PVFVfunc)看名字应该是个函数,运行时点上看时出现下面一行字符“dynamic atexit destructor for ‘theApp’(void)”不知道毛意思。先不管了,走着。接下来有句return (_onexit((_onexit_t)func) ==NULL) ? -1 : 0;好像要根据func来返回个值,我感觉这个函数是在程序退出时才会返回的。进入到_onexit。跳转(11)。

(11)_onexit(atonexit.c)中有一佗子不想看的东西,直接让他暂不深究了。出现个意外,当我在_lock(_EXIT_LOCK1);上设置断点执行后,居然会跳到了CCmdTarget的构造函数中。然后发现_onexit这个函数会不断的执行,于是直接在return处设断点后单步调试。发现跳到了PROCESS_LOCAL(_AFX_OLE_STATE,_afxOleState)(oledata.cpp)。这之间又回到了一次theApp这个全局对象处。蛋疼!你妹,一进C运行时库让哥怎么跟。

(12)下面重新从WinMain函数开始跟。

(13)appmodule中有_tWinMain他实际上就是wWinMain的一个宏。函数里调用全局函数AfxWinMain。跳转(14)。

(14)AfxWinMain的四个参数与WinMain相同,CWinThread* pThread = AfxGetThread();CWinApp*pApp =AfxGetApp();得到App和Thread。调用初始化函数。AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow)。跳转(15)。执行pApp->InitApplication()。跳到(16)。pThread->InitInstance()。进入到了CStudyFrameApp::InitInstance(),跳转(17)。调用nReturnCode = pThread->Run();这个Run中调用了CWinThread::Run();跳转(19)。

(15)AfxWinInit在appinit.cpp中。先将theApp填充,添加一些DLL。事实上,这个函数比tWinMain更早执行过,只是这时又调用了一遍。回到(14)。

(16)pApp->InitApplication()里面定义了一些文档信息。回到(14)。

(17)CStudyFrameApp::InitInstance()。调用CWinAppEx::InitInstance();跳转(18)。添加了一些管理器(Manager)。定义了一个文档模板类CSingleDocTemplate*pDocTemplate;并用单文档模板来构造之,构造函数的参数是文档类,框架类,View类,还有个宏IDR_MAINFRAME,这个宏实际上代表很多资源。将模板对象加入到App类的文档管理器中,AddDocTemplate(pDocTemplate);然后就有m_pMainWnd->ShowWindow(SW_SHOW);显示出窗口了,什么时候注册的窗口类?创建的窗口?回到(14)。

(18)CWinAppEx::InitInstance();中设置一些DLL信息后就返回。回到(17)。

(19)CWinThread::Run(),又要得到线程状态。在这里面进行消息循环。

(20)消息处理在哪里呢?根据Win32 SDK的知识,消息处理是在CreateWindow的参数中注册了一个消息处理函数,那么CreateWindow函数在哪里呢?

(21)在CWinApp中有关于CWnd的信息,包括创建窗口,消息处理等。找到了AfxCtxCreateWindowEx这个全局函数,应该是创建窗口用的,一跟进去到文件afxcomctl32.cpp中,相当复杂。