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

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

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

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

       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.   
  8.        if (!pThread->InitInstance())   
  9.        {   
  10.               .........略   
  11.        }   
  12.   
  13.        // Run函数位于THRDCORE.cpp中,由此函数进入消息循环   
  14.        nReturnCode = pThread->Run();   
  15.   
  16.        ..............略   
  17.   
  18.        return nReturnCode;   
  19. }   

       上面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.       
  15.        CCommandLineInfo cmdInfo;       
  16.        ParseCommandLine(cmdInfo);       
  17.       
  18.        //ProcessShellCommand位于AppUI2.cpp中,注册并创建窗口       
  19.        if (!ProcessShellCommand(cmdInfo))       
  20.              return FALSE;       
  21.       
  22.        m_pMainWnd->ShowWindow(SW_SHOW);       
  23.        m_pMainWnd->UpdateWindow();       
  24.       
  25.        return TRUE;       
  26. }      

       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.       
  11.               // reset "no idle" state after pumping "normal" message       
  12.               if (IsIdleMessage(&m_msgCur))       
  13.               {       
  14.                      bIdle = TRUE;       
  15.       
  16.                      lIdleCount = 0;       
  17.       
  18.               }       
  19.        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));       
  20.        ..............略       
  21. }       
  22.         
  23. BOOL CWinThread::PumpMessage()       
  24. {     
  25.        return AfxInternalPumpMessage();    
  26. }    
  27.   
  28. BOOL AFXAPI AfxInternalPumpMessage()   
  29. {   
  30.        _AFX_THREAD_STATE *pState = AfxGetThreadState();   
  31.       
  32.        if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))          
  33.        {       
  34.              .............略       
  35.        }       
  36.        ...............略       
  37.        if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))   
  38.        {   
  39.              ::TranslateMessage(&(pState->m_msgCur));   
  40.              ::DispatchMessage(&(pState->m_msgCur));   
  41.        }     
  42.       
  43.        return TRUE;       
  44. }       

       我们看到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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2022年中国中小学教育信息化行业研究报告

教育信息化丨研究报告 核心摘要&#xff1a; 背景篇 目前&#xff0c;我国中小学教育主要呈现信息时代教育的特征&#xff0c;智能时代教育特征初露端倪&#xff1b;中小学教育信息化正从量变迈向质变&#xff0c;创新引领与生态变革成为行业纵深的主旋律&#xff1b; 2021年…

使用curl指令发起websocket请求

昨日的文章没指出websocket请求协商切换的精髓&#xff0c;删除重发。前文相关&#xff1a;• .NET WebSockets 核心原理初体验[1]• SignalR 从开发到生产部署避坑指南[2]tag&#xff1a;浏览器--->nginx--> server其中提到nginx默认不会为客户端转发Upgrade、Connectio…

Yii 2 的安装 之 踩坑历程

由于刚接触yii2 ,决定先装个试试&#xff1b;可是这一路安装差点整吐血&#xff0c;可能还是水平有限吧&#xff0c; 但还是想把这个过程分享出来&#xff0c;让遇到同样问题的同学有个小小的参考&#xff0c;好了言归正传&#xff01;&#xff01; <(~.~)> 下面是安装流…

设计模式之代理模式(上) 静态代理与JDK动态代理

2019独角兽企业重金招聘Python工程师标准>>> 代理模式 给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。静态代理 静态代理是由我们编写好的类&#xff0c;在程序运行之前就已经编译好的的类&#xff0c;此时就叫静态代理。 说理论还是比较懵…

WPF 实现更换主题色

WPF 实现更换主题色WPF 使用 WPFDevelopers.Minimal 如何更换主题色作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visual Studio 2022;项目使用 MIT 开源许可协议&a…

vue3与vue2的区别

先来说说当下市场开发使用的问题&#xff0c;目前2021年使用vue3开发的企业还是少&#xff0c;基本上都还是以vue2的形式进行开发&#xff0c;vue3的开发模式跟react很像&#xff0c;这时候有人就会想那我学vue3有用么&#xff0c;淦&#xff0c;他喵的&#xff0c;先别激动&am…

Spring Data REST API集成Springfox、Swagger

原文: Documenting a Spring Data REST API with Springfox and Swagger 使用Spring Date REST&#xff0c;你可以迅速为Spring Date repositories的创建REST API&#xff0c;并提供CRUD和更多功能。然而&#xff0c;在严谨的API开发过成功&#xff0c;您还希望拥有自动生成的最…

【系统设计】S3 对象存储

在本文中&#xff0c;我们设计了一个类似于 Amazon Simple Storage Service (S3) 的对象存储服务。S3 是 Amazon Web Services (AWS) 提供的一项服务&#xff0c; 它通过基于 RESTful API 的接口提供对象存储。根据亚马逊的报告&#xff0c;到 2021 年&#xff0c;有超过 100 万…

转: telnet命令学习

1.每天一个linux命令&#xff08;58&#xff09;&#xff1a;telnet命令 转自&#xff1a; http://www.cnblogs.com/peida/archive/2013/03/13/2956992.html telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员&a…

禅道、码云、coding、redmine、jira、teambition几大敏捷开发项目管理系统试用对比体验

作为一个软件公司的管理人员&#xff0c;在项目和人员多起来后&#xff0c;就需要通过系统来对项目和人员进行管理。 我们是典型的软件外包公司&#xff0c;专为客户定制软件&#xff0c;所以我们的业务都是项目型的。因此&#xff0c;在管理模式上&#xff0c;我们就要用所谓…

Dubbo中的SPI机制

Dubbo中的SPI机制 概述 Service Provider Interface 即 SPI&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;可以用来启用框架扩展和替换组件。可以让不同的厂商针对统一接口编写不同的实现 SPI实际上是“接口策略模式配置文件”实现的动态加载机制。在系统设计中&…

JWT:拥有我,即拥有权力

Hi&#xff0c;这里是桑小榆。上篇文章中&#xff0c;我们一起探讨了 OAuth 协议的原理以及授权认证流程&#xff0c;本次我们一起探讨 jwt 令牌作为授权协议的传输介质。OAuth协议规范了几个参与角色的授权标准&#xff0c;安全可控的授予第三方应用&#xff0c;第三方应用获取…

双十一到来之前,阿里AI设计师“鲁班”1天能做4000万张海报

相比较去年&#xff0c;“鲁班”的设计技艺有所提升。 人工智能很大程度上便利了我们的生活&#xff0c;现在他们甚至还能取代了一些设计师的工作&#xff0c;在双十一正式到来之前&#xff0c;淘宝的宣传已经铺天盖地&#xff0c;然而很多人都没想到&#xff0c;我们打开淘宝…

Appium移动自动化测试之获取appPackage和appActivity

方法一&#xff1a;直接打开Appium,点击左上角机器人图标 选择apk所在位置&#xff0c;如图所示&#xff0c;这里以ContactManager.apk为例 方法二&#xff1a;利用dex2jar和jd-gui这两个工具反编译apk文件 这里仍以ContactManager.apk为例 (1)重命名ContactManager.apk为Conta…

CAD转WPF: 关于CAD图纸文件转换为WPF矢量代码文件(xaml文件)的技巧

前言&#xff1a;下面的文章&#xff0c;我将会以几个很简单的步骤&#xff0c;来演示一下通过CAD图纸转换为XAML代码文件的方法&#xff0c;供大佬们参考。一、为了演示一个简单的操作&#xff0c;我此处先打开一个空白的CAD&#xff0c;等下用来进行绘制点内容使用。二、自定…

python之新式类与经典类

经典类与新式类经典类:P 或 P()--深度查找&#xff0c;向上查父节点新式类 :P(object)---广度查找&#xff0c;继承object&#xff0c;新式类的方法较多转载于:https://www.cnblogs.com/zyy98877/p/8574983.html

Flowportal-BPM——环境配置

环境配置&#xff1a; 一、控制面板→程序和功能→打开或不关闭Window功能→选择选项 二、控制面板→管理工具→Internet信息服务&#xff08;IIS&#xff09;管理器→左侧第一个→ISAPI和CGI限制→全部选为【允许】 三、控制面板→管理工具→Internet信息服务&#xff08;IIS&…

一篇文章带你搞懂什么是DevOps?

DevOps DevOps 它的英文发音是 /de’vɒps/&#xff0c;类似于“迪沃普斯”&#xff0c;一词本身是对于 development 以及 operation 两个词的混合&#xff0c;其目的在于缩短系统开发的生命周期&#xff0c;在这过程中发布特性、修复bug以及更新均被紧密的结合。 简化的含义为…

微服务架构下分布式事务解决方案 —— 阿里GTS

1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务&#xff0c;这样可以降低开发难度、增强扩展性、便于敏捷开发。当前被越来越多的开发者推崇&#xff0c;很多互联网行业巨头、开源社区等都开始了微服务的讨论和实践。Hailo有160个不同服务构成&…

重要消息丨.NET Core 3.1 将于今年12月13日结束支持

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;5分钟).NET Core 3.1 将于 2022 年 12 月 13 日结束支持。此后&#xff0c;Microsoft 将不再为 .NET Core 3.1 提供服务更新或技术支持。我们建议尽快迁移到 .NET 6。如果您在支持日期结束后仍在使用 .NET Core 3.1&a…