VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 512|回复: 0

[分享] 浅谈MFC框架内部结构 一

[复制链接]
08_avatar_middle
最佳答案
10 
在线会员 发表于 2022-4-2 18:11:51 | 显示全部楼层 |阅读模式
本帖最后由 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窗口代码:
  1. #include <afxwin.h>
  2. class MyApp :public CWinApp
  3. {
  4. public:
  5.         MyApp(){}
  6.         virtual BOOL InitInstance();
  7. };

  8. class MyWnd :public CFrameWnd
  9. {
  10. public:
  11. };

  12. BOOL MyApp::InitInstance()
  13. {
  14.         MyWnd* pFrame = new MyWnd();
  15.         m_pMainWnd = pFrame;
  16.         pFrame->Create(NULL, "Window");
  17.         pFrame->ShowWindow(SW_SHOW);
  18.         pFrame->UpdateWindow();
  19.         return TRUE;
  20. }
  21. MyApp theApp;
复制代码

在下三个断点:
  1. MyApp theApp;
  2. MyApp(){}
  3. BOOL MyApp::InitInstance()
复制代码

F5调试运行,停在
MyApp theApp;
F5继续运行,进入构造函数,F11在进入父类构造函数查看代码显示
CWinApp::CWinApp(LPCTSTR lpszAppName)
声明父类CWinApp构造函数时候 参数已经给NULL了:
explicit CWinApp(LPCTSTR lpszAppName = NULL);
复制代码并提取我们所要的信息为:
  1. CWinApp::CWinApp(LPCTSTR lpszAppName)
  2. {
  3. m_pszAppName = NULL;

  4.         AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
  5. //假设 变量名为: _module_state
  6.         AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
  7. //假设 变量名为: _module_thread

  8.         ASSERT(AfxGetThread() == NULL);
  9. //判断线程是否为空  下面有函数解开的流程

  10.         pThreadState->m_pCurrentWinThread = this;
  11. //_module_thread 存储了this 指针 this == theApp
  12. //下面继续判断 里面是否真的储存了 this指针

  13.         ASSERT(AfxGetThread() == this);
  14. //判断线程是否自己的  下面有函数解开的流程

  15.         m_hThread = ::GetCurrentThread();
  16.         m_nThreadID = ::GetCurrentThreadId();

  17.         // initialize CWinApp state
  18.         ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
  19. //按照注释给出的 只有一个CWinApp 对象

  20.         pModuleState->m_pCurrentWinApp = this;
  21. //把this 保存到 _module_state里面
  22.         ASSERT(AfxGetApp() == this);
  23. //AfxGetApp()里面是这个 宏 afxCurrentWinApp
  24. //afxCurrentWinApp == AfxGetModuleState()->m_pCurrentWinApp
  25. //1、其实 就是上面的代码pModuleState->m_pCurrentWinApp
  26. //2、* pModuleState = _AFX_CMDTARGET_GETSTATE()
  27. //3、_AFX_CMDTARGET_GETSTATE() <==> AfxGetModuleState()
  28. }
复制代码


_AFX_CMDTARGET_GETSTATE() <==> AfxGetModuleState()宏里面就是这个函数,函数据说是保存了程序的模块信息和线程信息,是个全局变量。微软并没有公开显示文档,只是说 提供了一些Afx函数让你去调用就可以获取信息。
  1. CWinThread* AFXAPI AfxGetThread()
  2. {
  3.         // check for current thread in module thread state
  4.         AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  5. //获取的是_module_thread 变量        下面解释下这个函数

  6.         CWinThread* pThread = pState->m_pCurrentWinThread;
  7.         return pThread;//返回的就是 CWinApp 的this指针本身
  8. }

  9. AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()
  10. {
  11.         AFX_MODULE_THREAD_STATE* pResult=AfxGetModuleState()->m_thread.GetData();
  12. //这里的pResult 和 CWinApp的pThreadState 是一个地址!!!

  13.         ENSURE(pResult != NULL);
  14.         return pResult;
  15. }
复制代码

到这里为止 CWinApp的构造函数执行完毕 总结下 做了什么事情:
1、给MyApp的各个成员赋值,继承自父类的
浅谈MFC框架内部结构   一
2、把程序状态信息/线程状态信息保存到 两个变量里面(变量微软未公开,假设变量名)。
(1)_module_state
(2)_module_thread
重新调试运行程序。直接F5到theApp,按F5到构造函数,因为已经跟过了继续按F5到InitIstance()函数这里停下。现在有一个疑问。这个函数是谁调用的?构造函数是因为创建对象,必须被调用的。查看下堆栈查看 发现:
浅谈MFC框架内部结构   一
是AfxWinMain()函数调用的InitInstance(),WinMain()调用的AfxWinMain()。所以跟进去看看。
下断点并结束运行。(因为 AfxWinMain()函数已经调用了InitInstance()了,我们得停在AfxWinMain()函数这里)!!!
浅谈MFC框架内部结构   一
重新运行调试F5之后两次F5停在了 AfxWinMain()函数这里,进入分析它做了什么事情。
复制代码并提取我们所要的信息为:
  1. int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  2.         _In_ LPTSTR lpCmdLine, int nCmdShow)
  3. {
  4.         CWinThread* pThread = AfxGetThread();//获取this指针呢 就是theApp
  5.         CWinApp* pApp = AfxGetApp();//获取this指针呢 就是theApp
  6. //上面有这两个函数的解释

  7. pApp->InitApplication();//初始化程序
  8. pThread->InitInstance();//这是个虚函数,初始化程序 进入我们自己重写的函数
  9. //上面两句代码执行失败都是走 goto InitFailure;

  10. nReturnCode = pThread->Run();//这里其实是消息循环
  11. return nReturnCode;
  12. }
复制代码

评分

参与人数 2威望 +15 驿站币 +16 热心值 +4 收起 理由
75_avatar_small wl1383838438 + 15 + 15 + 3 赞一个!
03_avatar_small wsygcn + 1 + 1 大佬辛苦了

查看全部评分





上一篇:Bitmap如何转换为Mat
下一篇:浅谈MFC框架内部结构 二

本帖被以下淘专辑推荐:

您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

×【发帖 友情提示】
1、请回复有意义的内容,请勿恶意灌水;
2、纯数字、字母、表情等无意义的内容系统将自动删除;
3、若正常回复后帖子被自动删除,为系统误删的情况,请重新回复其他正常内容或等待管理员审核通过后会自动发布;
4、感谢您对VC驿站一如既往的支持,谢谢合作!

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号-4 )|网站地图wx_jqr

GMT+8, 2023-9-29 15:26

Powered by CcTry.CoM

© 2009-2021 cctry.com

快速回复 返回顶部 返回列表