百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

抽丝剥茧理解一个MFC 程序的生命过程(及与API的对比)

liebian365 2024-10-24 14:36 30 浏览 0 评论

以Windows API开发程序,程序从进入点开始,然后产生窗口类别、窗口、取得消息、分辨消息,然后决定如何处理消息:

以MFC 开发程序开发工具会为你产生一个骨干程序,一般该有的各种接口一应俱全:

MFC就是用C++语言的类来封装Windows API:

SDK 程序设计的第一要务是了解最重要的数个API 函数的意义和用法, 像RegisterClass、CreateWindow、GetMessage、DispatchMessage,以及消息的获得与分配。MFC 程序设计的第一要务则是熟记MFC 的类别阶层架构,并清楚知晓其中几个一定会用到的类别。

一个"Hello MFC" 程序的两个类别在MFC 的地位如下图所示:

每一个MFC程序都想从MFC中衍生出适当的类别来用(不然又何必以MFC写程序呢),其中两个不可或缺的类别CWinApp和CFrameWnd在Hello程序中会表现出来。

MFC类别中某些函数一定得被应用程序改写(例如CWinApp::InitInstance)。

Hello 程序的基本文件架构。一般习惯为每个类别准备一个.H( 声明)和一个.CPP(实作)。

SDK 程序的WinMain 所完成的工作现

在由CWinApp 的三个函数完成:

virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();

CFrameWnd::Create 产生主窗口(并先注册窗口类别)

CWinApp::Run

把消息与处理函数串接在一起:Message Map 机制

MFC 应用程序代码一开始是一个衍生自CWinApp 的全域对象application object,然后是一个隐藏的WinMain 函数,调用application object 的InitInstance 函数,将程序初始化。初始化动作包括构造一个窗口对象(CFrameWnd 物件),而其构造式又调用CFrameWnd::Create 产生真正的窗口(并在产生之前要求MFC注册窗口类别)。窗口产生后WinMain 又调用Run 激活消息循环,将WM_COMMAND(IDM_ABOUT)和WM_PAINT 分别交给成员函数OnAbout 和OnPaint 处理。

MFC 应用程序的诞生:

■ Application object 产生,内存于是获得配置,初值亦设立了。

■ Afx WinMain 执行AfxWinInit,后者又调用AfxInitThread,把消息队列尽量加大。

■ Afx WinMain 执行InitApplication。这是CWinApp 的虚拟函数,但我们通常不改写它。

■ AfxWinMain 执行InitInstance。这是CWinApp 的虚拟函数,我们必须改写它。

■ CMyWinApp::InitInstance 'new' 一个CMyFrameWnd 对象。

■ CMyFrameWnd 构造式调用Create,产生主窗口。我们在Create 参数中指定的窗口类别是NULL, 于是MFC 根据窗口种类, 自行为我们注册一个名为"AfxFrameOrView42d" 的窗口类别。

■ 回到InitInstance 中继续执行ShowWindow,显示窗口。

■ 执行UpdateWindow,于是发出WM_PAINT。

■ 回到AfxWinMain,执行Run,进入消息循环。

MFC 应用程序开始运作:

■ 程序获得WM_PAINT 消息(藉由CWinApp::Run 中的::GetMessage 循环)。

■ WM_PAINT 经由::DispatchMessage 送到窗口函数CWnd::DefWindowProc 中。

■ CWnd::DefWindowProc 将消息绕行过消息映射表格(Message Map)。

■ 绕行过程中发现有吻合项目,于是调用项目中对应的函数。此函数是应用程序利用BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间的宏设立起来的。

( 标准消息的处理例程亦有标准命名,例如WM_PAINT 必然由OnPaint 处理。)

MFC 应用程序的死亡:

■ 使用者选按【File/Close】,于是发出WM_CLOSE。

■ CMyFrameWnd 并没有设置WM_CLOSE 处理例程,于是交给预设之处理例程。

■ 预设函数对于WM_CLOSE 的处理方式是调用::DestroyWindow, 并因而发出WM_DESTROY。

■ 预设之WM_DESTROY 处理方式是调用::PostQuitMessage,因此发出WM_QUIT。

■ CWinApp::Run 收到WM_QUIT 后会结束其内部之消息循环, 然后调用ExitInstance,这是CWinApp 的一个虚拟函数。

■ 如果CMyWinApp 改写了ExitInstance , 那么CWinApp::Run 所调用的就是CMyWinApp::ExitInstance,否则就是CWinApp::ExitInstance。

■ 最后回到AfxWinMain,执行AfxWinTerm,结束程序。

附:VC中可调用的函数大致可分三类

1、类自己的函数,只对类自己的数据成员有作用。例如MFC中 MessageBox的原型,它是属于 CWnd 类的成员函数,只能在 CWnd 和CWnd的派生类的对象中调用;当然,也可以直接调用类中的其他成员函数;

2、AFX小组在设计Application Framworks 时设计的全局函数,多冠在Afx前缀,在包含了MFC库/框架的工程中可用。例如AfxMessageBox可在任何地方调用。

3、Windows API的全局函数。对所有Windows平台下的程序设计都可以调用,如Vb,Vc,Dephi等等。

参考:《深入浅出MFC》

-End-

相关推荐

C#夯实基础-Lambda在List中的使用

在C#中基本类型比如List,Dictionary,数组等都有委托来实现相关的操作。此时Lambda表达式就可以使用了.实例1,查找字符串List的包含a的元素...

在C#中,如何实现对集合中元素的自定义排序?

在C#中,可以通过多种方式实现对集合中元素的自定义排序,主要包括:...

C++11 新特性面试题_c++ 11 面试题

1、C++11中引入了哪些新的智能指针类型?请描述它们的用法和区别。C++11中引入了三种新的智能指针类型:std::unique_ptr,std::shared_ptr,和std::weak_...

为什么要使用lambda表达式?原来如此,涨知识了

为什么要使用Lambda表达式先看几段Java8以前经常会遇到的代码:创建线程并启动...

[编程基础] Python lambda函数总结

Pythonlambda函数教程展示了如何在Python中创建匿名函数。Python中的匿名函数是使用lambda关键字创建的。...

硬核!Java 程序员必须掌握的 10 个 简化代码的 Lambda 表达式!

大家好,我是一位在架构师道路上狂奔的码农,今天给大家介绍一下程序员必须掌握的10个Lambda表达式,这些表达式几乎涵盖了在实际编程中经常用到的常见场景。相信通过这10个Lambda表...

一文读懂lambda表达式_lambda表达式由来

作者:youngyan,腾讯PCG数据工程工程师...

Java基础知识 - lambda 表达式_javalambda表达式用法

1、表达式语法1)lambda的命名采用的是数学符号λ;...

Python学习笔记 | 匿名函数lambda、映射函数map和过滤函数filter

什么是匿名函数?定义:没有函数名的自定义函数场景:函数体非常简单,使用次数很少,没有必要声明函数,通常搭配高阶函数使用。...

Java Lambda表达式详解(非常全面)

JavaLambda表达式是JDK8引入的,是一个比较重要的特性。@mikechenLambda表达式简介...

Python函数—lambda表达式_python中lambda函数的用法讲解

目录...

了解 Lambda:Python 中的单个表达式函数

Python中的lambda关键字提供了声明小型匿名函数的快捷方式。Lambda函数的行为与使用...

在C#中使用Lambda编写一个排序算法,比较其与传统排序算法的优劣

使用Lambda表达式编写排序算法在C#中,Lambda表达式可以用来简化排序逻辑的编写,尤其是在需要自定义排序规则时非常方便。以下示例展示了如何用Lambda表达式实现排序,并与传统排...

一日一技:python中的匿名函数 lambda用法

匿名函数lambda,语法如下:lambdaarguments:expression...

《回炉重造》——Lambda表达式_回炉重造是贬义词吗

前言Lambda表达式(LambdaExpression),相信大家对Lambda肯定是很熟悉的,毕竟我们数学上经常用到它,即λ。不过,感觉数学中的Lambda和编程语言中的Lamb...

取消回复欢迎 发表评论: