zoukankan      html  css  js  c++  java
  • 【笔记】《深入浅出MFC》第6章 MFC程序的生死因果

    一、头文件说明

    STDAFX.H

    这个文件用来作为Precompile header file,其内只是载入其他的MFC头文件。应用程序通常会准备自己的头STDAFX.H。

    AFXWIN.H

    每一个Windows MFC程序都必须载入它,因为它以及它所载入的文件声明了所有的MFC类。

    在WINDEF.H中有CALLBACK的定义

    #define CALLBACK _stdcall     //是一种函数调用习惯

    在AFXWIN.H中有afx_msg的定义

    #define afx_msg        //故意安排一个空位置,也许以后版本会用到。

    所有MFC头文件均置于MSVCMFCINCLUDE中。这些文件在编译过程中耗费大量时间,所以有必要设定Precompiled header。一个应用程序在常需要不断地编译。Windows程序载入的.H文件非常巨大但内容不变,编译器浪费在上面的时间非常多。Precompiled header就是将.H文件第一次编译后的结果存储起来,第二次再编译时就可以直接从磁盘中取出来用。

    二、MFC程序的来龙去脉

    CWinApp代表程序本体。CFrameWnd代表一个主框架窗口。必须以这两个类为基础,派生自己的类,并改写其中一部分成员函数。

    全局对象theAPP,就是application object。每一个应用程序都应该改写CWinApp::InitInstance()函数。

    MFC把有着相当固定行为的WinMain内部操作封装在CWinApp中,把有着相当固定行为的WinProc内部操作封装在CFrameWnd中。

    传统SDK程序WinMain完成的工作,现在由CWinApp的三个函数完成。

    Virtual BOOL InitApplication();

    Virtual BOOL InitInstance();

    Virtual int Run();

    CWinApp继承CWinThread了成员变量m_pMainWnd,代表主窗口。CFrameWnd主要用来掌握一个窗口,它是用来取代SDK程序中的窗口函数的地位。

    我们并未写WinMain程序代码,这是MFC早已准备好并由链接器直接加到应用程序代码中的。_tWinMain函数的_t是为了支持UniCode而准备的一个宏。

    下面是AfxWinMain代码。

    将以上代码整理一下就得到下面这段代码。

    AfxGetApp 是一个全局函数,它取得CMyWinApp 对象指针。AfxWinInit 是继CWinApp 构造式之后的第一个动作。AfxWinInit 之后的动作是pApp->InitApplication。

    以上代码这些动作都是MFC 为了内部管理而做的。继InitApplication 之后, AfxWinMain 调用pApp->InitInstance。

    一般而言,CMyWinApp只改写CWinApp中的InitInstance,通常它不改写InitApplication和Run。

    注意:应用程序一定要改写虚拟函数InitInstance,因为它在CWinApp 中只是个空函数,没有任何内建(预设)动作。

    CMyWinApp::InitInstance 一开始new 了一个CMyFrameWnd 对象,准备用作主框窗口的C++ 对象。CFrameWnd::Create 在产生窗口之前,会先引发窗口类别的注册动作。

    下面是CreateEx代码。

    调用的PreCreateWindow 是虚拟函数, CWnd 和CFrameWnd 之中都有定义。由于this 指针所指对象的缘故,这里应该调用的是CFrameWnd::PreCreateWindow。

    利用AfxDeferRegisterClass宏注册窗口类。不同类别的PreCreateWindow 成员函数都是在窗口产生之前一刻被调用,准备用来注册窗口类别。

    CMyFrameWnd::CMyFrameWnd 结束后, 窗口已经诞生出来;程序流程又回到CMyWinApp::InitInstance ,于是调用ShowWindow 函数令窗口显示出来,并调用UpdateWindow 函数令Hello 程序送出WM_PAINT 消息。

    窗口类别注册好了,窗口诞生并显示出来了, UpdateWindow 被调用,使得消息队列中出现了一个WM_PAINT 消息,等待被处理。现在,执行pApp->Run。

    Message Map 机制是为了提供更方便的程序接口(例如宏或表格),让程序员很方便就可以建立起消息与处理例程的对应关系。

    MFC 提供给应用程序使用的「很方便的接口」是两组宏。以Hello 的主窗口为例,第一个动作是在HELLO.H 的CMyFrameWnd 加上DECLARE_MESSAGE_MAP:

    第二个动作是在HELLO.CPP 的任何位置(当然不能在函数之内)使用宏如下:

    MFC 把消息主要分为三大类, Message Map 机制中对于消息与函数间的对映关系也明定以下三种:

    1、标准Windows 消息(WM_xxx)的对映规则:

    2、命令消息( WM_COMMAND)的一般性对映规则是:ON_COMMAND(<id>,<memberFxn>)

    例如:

    ON_COMMAND(IDM_ABOUT, OnAbout)

    ON_COMMAND(IDM_FILENEW, OnFileNew)

    ON_COMMAND(IDM_FILEOPEN, OnFileOpen)

    ON_COMMAND(IDM_FILESAVE, OnFileSave)

    3、Notification 消息(由控制组件产生,例如BN_xxx)的对映机制的宏分为好几种(因为控制组件本就分为好几种),以下各举一例做代表:

    各个消息处理函数均应以afx_msg void 为函数类型。如果某个消息在Message Map 中找不到对映记录,它会往基础类别流窜,这个消息流窜动作称为Message Routing。如果一直窜到最基础的类别仍找不到对映的处理例程,由默认函数来处理。

    【总结】

    凡是由你设计而却由Windows 系统调用的函数,统称为callback 函数。这些函数都有一定的类型,以配合Windows的调用动作。

    callback 函数是给Windows 调用的, Windows 并不经由任何对象调用这个函数,也就没有传递this 指针给callback 函数,于是导至堆栈中有一个随机变量会成为this 指针,而其结果当然是程序的崩溃了。

    要把某个函数用作callback 函数,两个方法可以做到这一点:

    (1)不要使用类的成员函数(也就是说,要使用全局函数)做为callback 函数。

    (2)使用static 成员函数。也就是在函数前面加上static 修饰词。

  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/mengwang024/p/4927378.html
Copyright © 2011-2022 走看看