上一讲鸡啄米讲的是VS2010应用程序工程中文件的组成结构,可能大家对工程的运行原理还是很模糊,理不出头绪,毕竟跟C++编程入门系列中的例程差别太大。这一节鸡啄米就为大家分析下MFC应用程序框架的运行流程。

一.SDK应用程序与MFC应用程序运行过程的对比

程序运行都要有入口函数,在之前的C++教程中都是main函数,而Windows应用程序的入口函数是WinMain函数,MFC程序也是从WinMain函数开始的。下面鸡啄米就给出用Windows SDK写的“HelloWorld”程序,与应用程序框架进行对比,这样能更好的了解框架是怎样运行的。Windows SDK开发程序就是不使用MFC类库,直接用Windows API函数进行软件开发。鸡啄米不是要讲解SDK开发,只是为了对比而简单介绍,至于SDK开发可以在大家学完MFC以后选择是否要研究,一般来说有简单了解就可以了。

SDK应用程序

首先,给出Windows SDK应用程序“HelloWorld”的源码:

C++代码
  1. #include <windows.h>
  2. LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);
  3. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
  4. {
  5. const static TCHAR appName[] = TEXT("Hello world");
  6. WNDCLASSEX myWin;
  7. myWin.cbSize = sizeof(myWin);
  8. myWin.style = CS_HREDRAW | CS_VREDRAW;
  9. myWin.lpfnWndProc = myWndProc;
  10. myWin.cbClsExtra = 0;
  11. myWin.cbWndExtra = 0;
  12. myWin.hInstance = hInstance;
  13. myWin.hIcon = 0;
  14. myWin.hIconSm  = 0;
  15. myWin.hCursor = 0;
  16. myWin.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  17. myWin.lpszMenuName = 0;
  18. myWin.lpszClassName = appName;
  19. //Register
  20. if (!RegisterClassEx(&myWin)) return 0;
  21. const HWND hWindow = CreateWindow(
  22. appName,
  23. appName,
  24. WS_OVERLAPPEDWINDOW,
  25. CW_USEDEFAULT,
  26. CW_USEDEFAULT,
  27. CW_USEDEFAULT,
  28. CW_USEDEFAULT,
  29. 0,
  30. 0,
  31. hInstance,
  32. 0);
  33. ShowWindow(hWindow,iCmdShow);
  34. UpdateWindow(hWindow);
  35. {
  36. MSG msg;
  37. while(GetMessage(&msg,0,0,0))
  38. {
  39. TranslateMessage(&msg);
  40. DispatchMessage(&msg);
  41. }
  42. return (int)msg.wParam;
  43. }
  44. }
  45. LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
  46. {
  47. if (msg==WM_PAINT)
  48. {
  49. PAINTSTRUCT ps;
  50. const HDC hDC = BeginPaint(hWindow,&ps);
  51. RECT rect;
  52. GetClientRect(hWindow,&rect);
  53. DrawText(hDC,TEXT("HELLO WORLD"),-1,&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  54. EndPaint(hWindow,&ps);
  55. return 0;
  56. }
  57. else if (msg==WM_DESTROY)
  58. {
  59. PostQuitMessage(0);
  60. return 0;
  61. }
  62. return DefWindowProc(hWindow,msg,wParam,lParam);
  63. }

上面的程序运行的流程是:进入WinMain函数->初始化WNDCLASSEX,调用RegisterClassEx函数注册窗口类->调用ShowWindow和UpdateWindow函数显示并更新窗口->进入消息循环。关于消息循环再简单说下,Windows应用程序是消息驱动的,系统或用户让应用程序进行某项操作或完成某个任务时会发送消息,进入程序的消息队列,然后消息循环会将消息队列中的消息取出,交予相应的窗口过程处理,此程序的窗口过程函数就是myWndProc函数,窗口过程函数处理完消息就完成了某项操作或任务。本例是要显示“HELLO WORLD”字符串,UpdateWindow函数会发送WM_PAINT消息,但是此消息不经过消息队列而是直接送到窗口过程处理,在窗口过程函数中最终绘制了“HELLO WORLD”字符串。

MFC应用程序

下面是MFC应用程序的运行流程,通过MFC库中代码进行分析:

首先在HelloWorld.cpp中定义全局对象theApp:CHelloWorldApp theApp;。调用CWinApp和CHelloWorldApp的构造函数后,进入WinMain函数(位于appmodul.cpp中)。

C++代码
  1. extern "C" int WINAPI
  2. _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  3. _In_ LPTSTR lpCmdLine, int nCmdShow)
  4. #pragma warning(suppress: 4985)
  5. {
  6. // call shared/exported WinMain
  7. return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
  8. }

在TCHAR.h中,有此定义:#define _tWinMain   WinMain,所以这里的_tWinMain就是WinMain函数。它调用了AfxWinMain函数(位于WinMain.cpp中)。

C++代码
  1. int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
  2. {
  3. .............略
  4. // App global initializations (rare)
  5. if (pApp != NULL && !pApp->InitApplication())
  6. goto InitFailure;
  7. if (!pThread->InitInstance())
  8. {
  9. .........略
  10. }
  11. // Run函数位于THRDCORE.cpp中,由此函数进入消息循环
  12. nReturnCode = pThread->Run();
  13. ..............略
  14. return nReturnCode;
  15. }

上面InitInstance函数的代码如下:

C++代码
  1. BOOL CTestApp::InitInstance()
  2. {
  3. .............略
  4. CSingleDocTemplate* pDocTemplate;
  5. pDocTemplate = new CSingleDocTemplate(
  6. IDR_MAINFRAME,
  7. RUNTIME_CLASS(CTestDoc),
  8. RUNTIME_CLASS(CMainFrame),      // main SDI frame window
  9. RUNTIME_CLASS(CTestView));
  10. if (!pDocTemplate)
  11. return FALSE;
  12. AddDocTemplate(pDocTemplate);
  13. // Parse command line for standard shell commands, DDE, file open
  14. CCommandLineInfo cmdInfo;
  15. ParseCommandLine(cmdInfo);
  16. //ProcessShellCommand位于AppUI2.cpp中,注册并创建窗口
  17. if (!ProcessShellCommand(cmdInfo))
  18. return FALSE;
  19. m_pMainWnd->ShowWindow(SW_SHOW);
  20. m_pMainWnd->UpdateWindow();
  21. return TRUE;
  22. }

InitInstance中的ProcessShellCommand函数又调用了CMainFrame的LoadFrame函数注册并创建了窗口,执行完ProcessShellCommand函数以后,调用了m_pMainWnd的ShowWindow和UpdateWindow函数显示并更新框架窗口。这些是不是与上面的SDK程序十分类似?

接下来该是消息循环了,上面的AfxWinMain函数中调用了pThread的Run函数(位于THRDCORE.cpp中),在Run中包含了消息循环。Run函数的代码如下:

C++代码
  1. int CWinThread::Run()
  2. {
  3. .............略
  4. // phase2: pump messages while available
  5. do
  6. {
  7. // pump message, but quit on WM_QUIT
  8. if (!PumpMessage())
  9. return ExitInstance();
  10. // reset "no idle" state after pumping "normal" message
  11. if (IsIdleMessage(&m_msgCur))
  12. {
  13. bIdle = TRUE;
  14. lIdleCount = 0;
  15. }
  16. } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
  17. ..............略
  18. }
  19. BOOL CWinThread::PumpMessage()
  20. {
  21. return AfxInternalPumpMessage();
  22. }
  23. BOOL AFXAPI AfxInternalPumpMessage()
  24. {
  25. _AFX_THREAD_STATE *pState = AfxGetThreadState();
  26. if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
  27. {
  28. .............略
  29. }
  30. ...............略
  31. if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
  32. {
  33. ::TranslateMessage(&(pState->m_msgCur));
  34. ::DispatchMessage(&(pState->m_msgCur));
  35. }
  36. return TRUE;
  37. }

我们看到PumpMessage中通过调用GetMessage、TranslateMessage、DispatchMessage等建立了消息循环并投递消息。

窗口过程函数AfxWinProc形式如下:

C++代码
  1. LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)
  2. {
  3. ……
  4. CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);
  5. ReturnAfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);
  6. }

两者运行过程对比

到此,通过对比可以发现,MFC应用程序的运行流程与SDK程序是类似的,都是先进行一些初始化过程,再注册并创建窗口,然后显示、更新窗口,最后进入消息循环,消息都由窗口过程函数处理。现在大家是不是觉得有些头绪了?在运行流程上有基本的掌握即可。

二.MFC应用程序框架主要类之间的关系

在第二讲中,给大家演示了如何利用应用程序向导生成单文档应用程序框架,可以看到程序的基本框架和必要的代码都自动生成了,上一讲又讲解了文件组成结构,实际上在前面自动生成的框架中比较重要的类包括以下几个:CHelloWorldApp、CMainFrame、CHelloWorldDoc和CHelloWorldView,至于其他的类比如CClassView、CFileView等都是在框架窗口(CMainFrame)上创建的面板等,不是必要的。

鸡啄米就四个主要类的关系简单讲下,CHelloWorldApp类处理消息,将收到的消息分发给相应的对象。CMainFrame是视图CHelloWorldView的父窗口,视图CHelloWorldView就显示在CMainFrame的客户区中。视图类CHelloWorldView用来显示文档类CHelloWorldDoc中的数据,并根据对视图类的操作修改文档类的数据。一个视图类只能跟一个文档类相联系,而一个文档类可以跟多个视图类相联系。关于视图类和文档类的关系后面会详细讲解。

本节VC++/MFC编程入门教程内容比较多,主要是让大家对MFC应用程序的运行原理有大概的了解。对于以后的MFC开发有很多好处。如果有问题请在鸡啄米博客留言交流。谢谢。

原文地址:http://www.jizhuomi.com/software/145.html

转载于:https://www.cnblogs.com/wodehao0808/p/6702660.html

(转载)VS2010/MFC编程入门之四(MFC应用程序框架分析)相关推荐

  1. VS2010/MFC编程入门之四(MFC应用程序框架分析)

    上一讲鸡啄米讲的是VS2010应用程序工程中文件的组成结构,可能大家对工程的运行原理还是很模糊,理不出头绪,毕竟跟C++编程入门系列中的例程差别太大.这一节鸡啄米就为大家分析下MFC应用程序框架的运行 ...

  2. vs2010c语言窗口程序,VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)...

    上一节中鸡啄米讲了文档.视图和框架结构中各对象之间的关系,本节主要讲讲在MFC中如何分割窗口. 分割窗口概述 分割窗口,顾名思义,就是将一个窗口分割成多个窗格,在每个窗格中都包含有视图,或者是同一类型 ...

  3. VS2010/MFC编程入门之四十四:定时器Timer

    前面一节鸡啄米讲了CTime类和CTimeSpan类的使用,本节继续讲与时间有关的定时器.定时器并不是一个类,主要考虑到,提起时间的话就不能不说定时器,所以就把它放到CTime和CTimeSpan之后 ...

  4. Visual Studio/MFC编程入门之MFC常用类:CString类

    上一节讲了分割窗口的有关知识,本节开始讲解MFC的一些常用类,先来说说CString类.在内容开始前为大家介绍一款MFC界面开发控件: Xtreme Toolkit Pro | 免费下载:是屡获殊荣的 ...

  5. VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)

    上一节中鸡啄米讲了CDC类及其屏幕绘图函数,本节的主要内容是GDI对象之画笔CPen. GDI对象 在MFC中,CGdiObject类是GDI对象的基类,通过查阅MSDN我们可以看到,CGdiObje ...

  6. VS2010/MFC编程入门教程之目录和总结

    写这套VS2010/MFC编程入门教程历时八个月,时间比较长,都是鸡啄米在工作之余加班加点完成的.虽然有点累,但看到有这么多人过来支持鸡啄米,很是值得. 写每节教程我都力求讲明白,深入浅出的阐述每个知 ...

  7. VS2010/MFC 编程入门教程之目录和总结

    [原地址]:http://www.jizhuomi.com/software/257.html 鸡啄米这个网站不是很了解,但确实有很多好文章.自己工作需要,在vs2010 下学习mfc的知识,发现了这 ...

  8. VS2010/MFC编程入门

    近来鼓捣2D小游戏的过程中发现鸡啄米大神很好的MFC系列资料,在此汗颜将地址扒拉了过来,留待以后慢慢学习. VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解) (http://ww ...

  9. VS2010/MFC编程入门教程

    一.VS2010/MFC编程入门教程之目录       第一部分:VS2010/MFC开发环境       VS2010/MFC编程入门之前言        VS2010/MFC编程入门之一(VS20 ...

最新文章

  1. Java CSV文件读取、写入及追加
  2. 如何禁用请求库中的日志消息?
  3. java dto是什么_java项目中VO和DTO以及Entity,各自是在什么情况下应用的
  4. Matlab中newff函数使用方法和搭建BP神经网络的方法
  5. 七十五、栈+双指针,头条当年接雨水问题
  6. 关于graphviz绘制的点(dot)图在显示时中文乱码问题的解决方法(亲测)
  7. Java连接mysql出现SQL异常,MySQL 这样连接为何出现这样的异常
  8. 其他机器无法访问php,PHP 局域网其他机器无法访问的问题
  9. 数据结构-图的进阶代码
  10. Javascript基础 对象与方法的识别
  11. DataSet 读取Oracle 数据
  12. 身份证号校验、身份证照片解析(百度API)
  13. VS2017超有用秘钥(亲测)
  14. MATLAB dir函数文件名排序问题
  15. 【C++】C++格式化输出/输出格式控制/输出精度控制
  16. Linux进程管理四大工具ps \dstat\ top\ htop
  17. 前端开发神器VS Code安装教程
  18. 栈内存和堆内存的区别(一个笔试题的一部分)
  19. 初中算题可以使用计算机吗,初中生计算机考试试题总汇
  20. 云计算是什么意思?云计算管理平台有哪些?

热门文章

  1. 哈尔滨阳光计算机学院是不是黄了,黑龙江这4所野鸡大学,常被误认为是名校,实则害人不浅...
  2. 动态链接(指向运行时常量池的方法引用)
  3. mysql截取字符串中的部分内容_Mysql字符串截取及获取指定字符串中的数据
  4. Linux:分享50个实用的基础命令,欢迎收藏!
  5. 程序人生:一个员工的离职成本到底有多高,看完你就懂了!
  6. 计算机系统基础:设备管理知识笔记
  7. IIS 错误代码分析手册
  8. mybatis.xml文件
  9. IDEA 快捷键终极大全
  10. 洛谷 P1417 烹调方案 (01背包拓展)