|
本帖最后由 SummerGull 于 2022-4-2 18:21 编辑
本次写文档是基于SYC老大的《VC++高级班之窗口篇》的一些拓展
用VS2019自带的调试系统来分析MFC的一些原理内容。
这里只是简单的对MFC整体框架一些剖析。
主要针对的是MFC的六大机制:
启动/运行/消息映射/动态运行/动态创建/序列化。
MFC对话框的剖析,SDI和MDI的剖析。
这次大部分我还是想用伪代码去写;主要方便观看和方便整个流程的可观。
尽可能的简单化把必需要的内容写出来,不太重要的东西就暂时忽略过去了。
进入主题 MFC的入口点在哪里:
C/C++ 写控制台程序 我们已知的入口是 main()
WIN32 API的 已知入口是 WinMain()
那么MFC的 入口并没有发现 以上任何一个。结合孙鑫老师的书《VC++深入详解》第三版章节4.2.1指出
读者可以在这个项目中再查找一下WNDCLASS、CreateWindow等,你会发现仍然找不到。那么是不是 MFC 程序就不需要 WinMain 函数、设计窗口类,也不需要创建窗口了呢?当然不是。我们之所以看不见这些,是因为微软在MFC的底层框架类中封装了这些每一个窗口应用程序都需要的步骤,目的主要是为了简化程序员的开发工作,但这也给我们在学习和掌握MFC程序时造成了很多不必要的困扰。
孙鑫老师还指出 theApp全局对象 是关键点,那么我们在 the App对象上下断点开始调试。
首先写一份简单的MFC窗口代码:
- #include <afxwin.h>
- class MyApp :public CWinApp
- {
- public:
- MyApp(){}
- virtual BOOL InitInstance();
- };
- class MyWnd :public CFrameWnd
- {
- public:
- };
- BOOL MyApp::InitInstance()
- {
- MyWnd* pFrame = new MyWnd();
- m_pMainWnd = pFrame;
- pFrame->Create(NULL, "Window");
- pFrame->ShowWindow(SW_SHOW);
- pFrame->UpdateWindow();
- return TRUE;
- }
- MyApp theApp;
复制代码
在下三个断点:
- MyApp theApp;
- MyApp(){}
- BOOL MyApp::InitInstance()
复制代码
F5调试运行,停在
MyApp theApp;
F5继续运行,进入构造函数,F11在进入父类构造函数查看代码显示
CWinApp::CWinApp(LPCTSTR lpszAppName)
声明父类CWinApp构造函数时候 参数已经给NULL了:
explicit CWinApp(LPCTSTR lpszAppName = NULL);
复制代码并提取我们所要的信息为:
- CWinApp::CWinApp(LPCTSTR lpszAppName)
- {
- m_pszAppName = NULL;
- AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
- //假设 变量名为: _module_state
- AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
- //假设 变量名为: _module_thread
- ASSERT(AfxGetThread() == NULL);
- //判断线程是否为空 下面有函数解开的流程
- pThreadState->m_pCurrentWinThread = this;
- //_module_thread 存储了this 指针 this == theApp
- //下面继续判断 里面是否真的储存了 this指针
- ASSERT(AfxGetThread() == this);
- //判断线程是否自己的 下面有函数解开的流程
- m_hThread = ::GetCurrentThread();
- m_nThreadID = ::GetCurrentThreadId();
- // initialize CWinApp state
- ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
- //按照注释给出的 只有一个CWinApp 对象
- pModuleState->m_pCurrentWinApp = this;
- //把this 保存到 _module_state里面
- ASSERT(AfxGetApp() == this);
- //AfxGetApp()里面是这个 宏 afxCurrentWinApp
- //afxCurrentWinApp == AfxGetModuleState()->m_pCurrentWinApp
- //1、其实 就是上面的代码pModuleState->m_pCurrentWinApp
- //2、* pModuleState = _AFX_CMDTARGET_GETSTATE()
- //3、_AFX_CMDTARGET_GETSTATE() <==> AfxGetModuleState()
- }
复制代码
_AFX_CMDTARGET_GETSTATE() <==> AfxGetModuleState()宏里面就是这个函数,函数据说是保存了程序的模块信息和线程信息,是个全局变量。微软并没有公开显示文档,只是说 提供了一些Afx函数让你去调用就可以获取信息。
- CWinThread* AFXAPI AfxGetThread()
- {
- // check for current thread in module thread state
- AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
- //获取的是_module_thread 变量 下面解释下这个函数
- CWinThread* pThread = pState->m_pCurrentWinThread;
- return pThread;//返回的就是 CWinApp 的this指针本身
- }
- AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()
- {
- AFX_MODULE_THREAD_STATE* pResult=AfxGetModuleState()->m_thread.GetData();
- //这里的pResult 和 CWinApp的pThreadState 是一个地址!!!
- ENSURE(pResult != NULL);
- return pResult;
- }
复制代码
到这里为止 CWinApp的构造函数执行完毕 总结下 做了什么事情:
1、给MyApp的各个成员赋值,继承自父类的
2、把程序状态信息/线程状态信息保存到 两个变量里面(变量微软未公开,假设变量名)。
(1)_module_state
(2)_module_thread
重新调试运行程序。直接F5到theApp,按F5到构造函数,因为已经跟过了继续按F5到InitIstance()函数这里停下。现在有一个疑问。这个函数是谁调用的?构造函数是因为创建对象,必须被调用的。查看下堆栈查看 发现:
是AfxWinMain()函数调用的InitInstance(),WinMain()调用的AfxWinMain()。所以跟进去看看。
下断点并结束运行。(因为 AfxWinMain()函数已经调用了InitInstance()了,我们得停在AfxWinMain()函数这里)!!!
重新运行调试F5之后两次F5停在了 AfxWinMain()函数这里,进入分析它做了什么事情。
复制代码并提取我们所要的信息为:
- int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- _In_ LPTSTR lpCmdLine, int nCmdShow)
- {
- CWinThread* pThread = AfxGetThread();//获取this指针呢 就是theApp
- CWinApp* pApp = AfxGetApp();//获取this指针呢 就是theApp
- //上面有这两个函数的解释
- pApp->InitApplication();//初始化程序
- pThread->InitInstance();//这是个虚函数,初始化程序 进入我们自己重写的函数
- //上面两句代码执行失败都是走 goto InitFailure;
- nReturnCode = pThread->Run();//这里其实是消息循环
- return nReturnCode;
- }
复制代码
|
评分
-
查看全部评分
上一篇: Bitmap如何转换为Mat下一篇: 浅谈MFC框架内部结构 二
|