MFC程序的启动过程与相关函数执行顺序

合集下载

MFC 执行顺序

MFC 执行顺序

MFC的程序执行顺序很多刚学MFC的人都会被MFC给弄的晕头转向。

以前传统的C语言中的main()不见了,window sdk api 中的WinMain()函数也不见了,到底用MFC编写的程序是如何开始运行的呢?到底MFC有没有遵从最基本的C++的标准呢?到底MFC的代码运行的顺序又是怎么样的呢?那么多个文件,那么多函数,到底哪一个先运行,哪一个后运行,哪一个调用哪一个,哪一个又被哪一个调用(你看晕了吧?那么多“哪一个”^_^)?这里这么复杂,到底最真是的是怎么一回事呢?我开始学习的时候,也是一头雾水,什么都不明白,但是为了能先学习一些其他的,我囫囵吞枣的看了过去,先学习了CDIALOG和CVIEW的一些用法,并能编出了一个很简单的程序。

前几天,上网的时候,看到好多人都在看《孙鑫vc++讲座》视频教程,好像大家反应还不错,于是,我就去找个地方下载下来看了。

刚好今天看到了MFC的运行机制,里面讲到了MFC的运行顺序。

孙同学在视频中是利用实例,利用断点,然后不断的进行调试运行,以实事(实事胜于雄辩啊!!!)告诉我们,MFC是如何开始运行的。

下面,我就根据我看到的教程,和网上一些前辈整理出来的材料在整理:重点:MFC运行机制执行顺序各个函数用途以及调用顺序孙同学在视频中反复说明的是:MFC的程序和C语言的程序,从执行原理上说,是完全一致的。

抓住这一点,那么对于理解MFC程序的运行机制也就相对于简单了。

C中的main函数就相当于MFC中的WinMain函数。

感兴趣的可以利用VC的断点设置自己跟踪下面讲述的各个函数,就明白它的执行顺序了。

一、C语言程序执行步骤在C语言中,大约的步骤如下:1,全局变量内存分配例子如下:#include <iostream.h>int a=88;main(){cout<<a<<endl;}如果我们在main前设置断点,我们就会发现,在进入main之前,a就已经存在了。

MFC程序执行过程

MFC程序执行过程

很是空闲最近.转载一些东西吧..就当是复习...再不看看,就忘光了MFC 应用程序的操作步骤可归结为四步:(1) 创建应用程序对象theApp(2) 执行MFC提供的WinMain()函数(3) WinMain()调用InitInstance()函数,此函数创建文档模板,主框架窗口,文档和视图(4) WinMain()调用Run()函数,此函数执行主消息循环,以获取和分派Windows消息。

WinMain()是函数的入口点,该函数的主要任务是完成一些初始化的工作和维护了一个消息循环。

他们的工作流程如下:入口(WinMain())---->MyRegisterClass()---->InitInstance ()--->while消息循环。

函数由入口开始执行,之后调用 MyRegisterClass()注册窗口类,之后InitInstance ()生成并显示窗口,这样之后,就完成了一个窗口的初始化工作了(当然,在MyRegisterClass(),InitInstance ()中都需要调用相应的API函数来具体的实现),然后就是维护消息循环,至此,程序的基本结构就差不多建立了。

以后程序的运作就靠个消息循环来推动了.1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。

该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。

2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。

MFC流程

MFC流程

MFC流程MFC程序文件名为Test.所以产生的5个类分别为1、CAboutDlg继承于CDialog2、CMainFrame继承于CFrameWnd1、CTestApp继承于CWinApp1、CTestDoc继承于CDocument1、CTestView继承于CView一、窗口产生流程1、设计窗口类2、注册窗口类3、产生窗口4、显示窗口5、更新窗口二、MFC中的细节1、WinMain函数的地址在C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\APPMODUL.CPP文件中extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}其中_tWinMain是WinMain的宏定义如下: (此定义在文件C:\Program Files\Microsoft VisualStudio\VC98\Include\TCHAR.H中)#define _tWinMain WinMain而_tWinMain调用的是AfxWinMain.2、theApp全局对象先于WinMain运行产生全局对象,在程序入口函数WinMain加载时,系统就已经为全局变量或全局对象分配了存储空间,并为它们赋了初始值。

存放在静态数据区。

每一个MFC程序有且仅有一个从应用程序类(CWinApp)派生的类。

每一个MFC程序实例有且仅有一个该派生类的实例化对象,也就是theApp全局对象。

该对象表示应用程序本身。

由于在子类的构造之前会先调用其父类的构造函数。

MFC程序流程

MFC程序流程

MFC程序流程程序的诞生application object产生,内存于是获得配置,初值设立afxWinMain执行afxwinInit,调用afxInitThread把消息队列加大afxWinMain执行 InitApplication 是CWinApp的虚函数,通常不该写afxWinMain执行 InitInstance 是CWinApp的虚函数,必须改写CMyFrameWnd构造式调用Create ,产生窗口,回到InitInstance中继续执行ShowWindow 显示窗口执行UpdateWindow 发送WM_PAINT回到AfxWinMain 执行Run,进入循环。

程序开始运作程序获得WM_PAINT消息。

(藉由CWinApp::Run中的::GetMessage循环)WM_PAINT经由DispatchMessage送到窗口函数CWnd::DefWindowProc中。

CWnd::DefWindowProc将消息绕行过消息映射表格(Message Map)绕行过程中发现有吻合项目,于是调用项目中对应的函数,此函数是应用程序利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的宏设立起来的。

标准消息的处理历程亦有标准命名,例如WM_PAINT必然由OnPaint处理程序的死亡:使用者按关闭。

发送WM_CLOSECMyFrameWnd并没有设置WM_CLOSE处理例程,于是交给于设置之处理例程。

预设函数对于WM_CLOSE的处理方式是调用::DestroyWindow并因而发出WM_DESTROY预设之WM_DESTORY处理方式是调用::PostQuitMessge发出WM_QUITCWinApp::Run收到WM_QUIT后会结束内部消息循环,然后调用ExitInstance,CWinApp的虚函数如果CMyWinApp改写了ExitInstance,那么CWinApp::Run就调用CMyWinApp::ExitInstance.回到AfxWinMain 执行 AfxWinTerm,结束程序。

浅析MFC程序基本运行机制

浅析MFC程序基本运行机制

2. CWinApp — 应用程序类
就像标题所说的,CWinApp 的作用是用来产生 MFC 应用程序对象。每个 MFC 程序都要求存在一个派生 自 CWinApp 的子类作为应用程序的类,并且需要我们通过这个子类,改写某些虚函数。可见 CWinApp 的 重要性,显然,CWinApp 是一个很大的类,他得完成很多工作。 以下是 MFC7.1 的 CWinApp 的定义源代码的超精简版本(完整版在FC 的基本运行机制之前,先让我们来回忆一下使用 C++/SDK 写 Windows GUI 程序的顺序: 调用 WinMain 入口函数→注册窗口类→窗口实例化→建立消息循环→处理消息 可以说,几乎每个 Windows GUI 程序的建立和运行,都要经过上面的几个步骤,MFC 程序也不例外。但 是由于 MFC 是以 C++为基础,所以它势必会使用 OOP 思想进行架构。而这一切,都会导致我们研究 MFC 的方式会和 C++/SDK 有那么一点区别。 我们在下面会以 MFC 的 Class 为中心进行研究,而非 Windows 窗体的线性行为。这意味着我们得忍受在 几个类中跳来跳去。是的,你可能会感到身体不适,我同样有这种感觉,我从小就恨透了 goto…… 那么,就让我们先来看看使用 MFC 改如何创建一个简单的窗体,然后在逐步抽丝剥茧,剖析 MFC 程序 的基本运行机理。
/************************************************** ** Project:MFCAppUser ** File:MFCAppUser.cpp
** Edition:NULL ** Coder:KingsamChen [MDSA Group] ** Last Modify:2008-8-9 **************************************************/ #include <afxwin.h> // 必备的头文件,这个头文件间接包含了 windows.h class CMFCApp : public CWinApp // 继承 CWinApp { public: virtual BOOL InitInstance(); // 虚函数 // 这个函数必须重写 }; class CMFCAppWindow : public CFrameWnd { public: CMFCAppWindow() // 在构造函数里创建窗体~ { Create(NULL,"KC's Windows"); // 除前两个参数外,其他参数均有初始值 } // 下面是消息映射的东东 afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); // 左键双击的消息声明 afx_msg void OnPaint(); // WM_PAINT 消息声明 DECLARE_MESSAGE_MAP() // 消息映射宏 }; // MS 叫做消息映射表 BEGIN_MESSAGE_MAP(CMFCAppWindow, CFrameWnd) ON_WM_LBUTTONDBLCLK() ON_WM_PAINT() END_MESSAGE_MAP() // 对应的消息处理,类似 SDK 窗体里面的回调函数处理过程 void CMFCAppWindow::OnLButtonDblClk(UINT nFlags, CPoint point) { MessageBox("KC is a Fucker", NULL, MB_OK); } void CMFCAppWindow::OnPaint() { CPaintDC Paint(this); Paint.TextOut(0, 0, "This is a sample for MFC");

MFC 运行过程

MFC 运行过程

执行一个windows应用程序包括初始化,运行和终止三大任务,MFC中的应用类封装了windows应用程序要做的这三大任务,这三大任务对应的三个主要函数就是InitInstance(),Run()和ExitInstance()。

应用类的基类是CWinApp类,MFC AppWizard自动生成的应用程序框架中的应用类就是由CWinApp类派生的。

注:应用程序必须有而且只能有一个CWinApp派生类,而且这个类只能有一个对象,这个对象是一个全程对象,即theAppCWinApp类有下面几个关键的虚函数,可供用户重载:InitInstance(),Run(),ExitInstance(),OnIdle()其中InitInstance()函数是必须重载的,而通常情况下也只需要重载InitInstance(),其他函数用户根据需要决定是否重载。

由于InitInstance()必须重载,所以在MFC AppWizard自动生成的应用程序框架中就自动重载了应用程序运行过程:InitInstance() 注:因为AppWizard已经重载了InitInstance(),所以这里调用的InitInstance()就是程序中重载的InitInstance() Run()注:WinMain()函数隐藏在应用框架内部,是看不到的。

InitInstance()函数:顾名思义,InitInstance()函数就是初始化实例。

Windows对同一个应用程序可以运行多个实例。

比如,如果已经在运行任务管理器,用户还可以再一次或多次启动任务管理器。

这样,系统就有多个任务管理器同时在运行,这些运行着的任务管理器就是任务管理器应用程序的多个运行实例。

当每次启动某个应用程序的一个实例时,WinMain()函数都要调用InitInstance()函数。

Run()函数:应用程序的大部分时间都是在应用类的Run()成员函数中打转转。

WinMain()函数在调用InitInstance()函数进行初始化完毕之后,就调用Run()函数来处理消息循环。

MFC程序中消息以及函数的处理顺序简介

MFC程序中消息以及函数的处理顺序简介

MFC程序中消息以及函数的处理顺序简介MFC应用程序中处理消息的顺序1.AfxWndProc()该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc2.AfxCallWndProc() 该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数3.WindowProc()该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数4.OnWndMsg()该函数的功能首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数,对于WM_NOTIFY消息调用OnNotify()消息响应函数。

任何被遗漏的消息将是一个窗口消息。

OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。

如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数5.OnCommand()该函数查看这是不是一个控件通知(lParam参数不为NULL,如果lParam参数为空的话,说明该消息不是控件通知),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果他不是一个控件通知(或者如果控件拒绝映射的消息)OnCommand()就会调用OnCmdMsg()函数6.OnCmdMsg()根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。

例如:如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数MFC应用程序创建窗口的过程1.PreCreateWindow()该函数是一个重载函数,在窗口被创建前,可以在该重载函数中改变创建参数(可以设置窗口风格等等)2.PreSubclassWindow() 这也是一个重载函数,允许首先子分类一个窗口3.OnGetMinMaxInfo()该函数为消息响应函数,响应的是WM_GETMINMAXINFO消息,允许设置窗口的最大或者最小尺寸4.OnNcCreate()该函数也是一个消息响应函数,响应WM_NCCREATE消息,发送消息以告诉窗口的客户区即将被创建5.OnNcCalcSize()该函数也是消息响应函数,响应WM_NCCALCSIZE消息,作用是允许改变窗口客户区大小6.OnCreate()该函数也是一个消息响应函数,响应WM_CREATE消息,发送消息告诉一个窗口已经被创建7.OnSize()该函数也是一个消息响应函数,响应WM_SIZE消息,发送该消息以告诉该窗口大小已经发生变化8.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息说明窗口在移动9.OnChildNotify()该函数为重载函数,作为部分消息映射被调用,告诉父窗口即将被告知一个窗口刚刚被创建MFC应用程序关闭窗口的顺序(非模态窗口)1.OnClose()消息响应函数,响应窗口的WM_CLOSE消息,当关闭按钮被单击的时候发送此消息2.OnDestroy()消息响应函数,响应窗口的WM_DESTROY消息,当一个窗口将被销毁时,发送此消息3.OnNcDestroy()消息响应函数,响应窗口的WM_NCDESTROY消息,当一个窗口被销毁后发送此消息4.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作,被CWnd调用MFC应用程序中打开模式对话框的函数调用顺序1.DoModal()重载函数,重载DoModal()成员函数2.PreSubclassWindow()重载函数,允许首先子分类一个窗口3.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建4.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化5.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息,以告诉窗口正在移动6.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息,以允许改变对话框中控件的字体7.OnInitDialog()消息响应函数,响应WM_INITDIALOG消息,发送此消息以允许初始化对话框中的控件,或者是创建新控件8.OnShowWindow()消息响应函数,响应WM_SHOWWINDOW消息,该函数被ShowWindow()函数调用9.OnCtlColor()消息响应函数,响应WM_CTLCOLOR消息,被父窗口发送已改变对话框或对话框上面控件的颜色10. OnChildNotify()重载函数,作为WM_CTLCOLOR消息的结果发送MFC应用程序中关闭模式对话框的顺序1.OnClose()消息响应函数,响应WM_CLOSE消息,当"关闭"按钮被单击的时候,该函数被调用2.OnKillFocus()消息响应函数,响应WM_KILLFOCUS消息,当一个窗口即将失去键盘输入焦点以前被发送3.OnDestroy()消息响应函数,响应WM_DESTROY消息,当一个窗口即将被销毁时,被发送4.OnNcDestroy()消息响应函数,响应WM_NCDESTROY消息,当一个窗口被销毁以后被发送5.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作被CWnd调用打开无模式对话框的顺序1.PreSubclassWindow()重载函数,允许用户首先子分类一个窗口2.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建3.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化4.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息以告诉窗口正在移动5.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息以允许改变对话框中控件的字体。

mfc入门讲义

mfc入门讲义
属性’对话框,在‘标明’编辑框中输入该菜单 项的显示名称。
(3)在生成工程时,已生成了‘IDD_STU1_DIALOG’对话框 类。把该菜单加入到该对话框类:
在‘ResourceView’选项卡中,执行“双击 ‘IDD_STU1_DIALOG ’对话框标识符”,在‘编辑’窗体可 见该对话框轮廓图,执行“右击该对话框轮廓图空白处|属性”, 弹出‘对话 属性’对话框,在‘常规’选项卡中‘菜单’下拉 列表框上选择‘IDR_MENU1’。 (4)执行IDE菜单命令“组建|执行”,可见本工程应用程序的 运行窗体上显示该菜单。
在‘ResourceView’选项卡中,执行“双击 ‘IDD_DIALOG1’对话框标识符”,在‘编辑’窗体可见该对 话框轮廓图,执行“双击该对话框轮廓图空白处”,弹出 ‘Adding a class’对话框;按‘OK’按钮,弹出‘New Class’对 话框,在‘name’编辑框中输入新类名为‘newdlg1’,按‘ok’按 钮;在出现的‘MFC ClassWizard ’对话框中按‘确定’按钮。
2.处理菜单消息
当点击菜单项时会产生消息,该消息会传递到菜单所在窗口,
如果该窗口类设置接受和处理该消息的函数,窗口对象会查到 该类对象对该消息的处理函数。 (1)菜单项标识符(ID)的查找
在IDE ‘工作空间’ 窗体的‘ResourceView’选项卡中, Menu资源下可见一个ID (标识符)为IDR_MENU1的菜单资源。 双击该ID,在IDE工作区会显示该菜单的框架,双击菜单项会 弹出‘菜单项目 属性’对话框,在该对话框中可知道该菜单项 ID。 (2)建立接受菜单项消息的类和消息处理函数
//dxdlg1的窗体
(3)无模式对话框的窗体删除 对话框类对象有一个删除对话框成员函数: virtual BOOL DestroyWindow( ); 例如: dxdlg1. DestroyWindow( ); //删除对话框对象的窗体

MFC启动和关闭线程

MFC启动和关闭线程

MFC启动和关闭线程1、启动线程:CWinThread* AfxBeginThread( 线程函数,this );2、通常导致线程终⽌的两种情况是:控制函数退出或不允许线程完成运⾏。

如果字处理器使⽤后台打印线程,若成功完成打印,则控制函数将正常终⽌。

但是,如果⽤户要取消打印,后台打印线程则不得不提前终⽌。

本主题介绍如何实现每⼀种情况,以及在终⽌后如何获取线程的退出代码。

(1)正常线程终⽌对于辅助线程,正常线程终⽌很简单:退出控制函数并返回表⽰终⽌原因的值。

可以使⽤函数或 return 语句。

⼀般情况下,0 表⽰成功完成,但这取决于您⾃⼰。

对于⽤户界⾯线程,该过程也很简单:从⽤户界⾯线程内调⽤ Platform SDK 中的。

PostQuitMessage 采⽤的唯⼀参数是线程的退出代码。

对于辅助线程,0 通常表⽰成功完成。

(2)过早的线程终⽌过早终⽌线程⼏乎⼀样简单:从线程内调⽤。

将所需的退出代码作为唯⼀参数传递。

这将停⽌执⾏线程、解除对线程堆栈的分配、分离附加到线程的所有 DLL 并从内存中删除线程对象。

必须从要终⽌的线程内调⽤ AfxEndThread。

如果要从其他线程终⽌线程,必须设置两个线程间的通信⽅法。

举⼀个例⼦:可以创建⼀个信号量,⽤WaitForSingleObject函数来检测该信号量的状态。

成员变量 m_hThreadEvent;m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );线程的执⾏函数:for( ; ;){DWORD dwRetVal;dwRetVal = WaitForSingleObject( m_hThreadEvent, 100 );if ( dwRetVal == WAIT_TIMEOUT ){// TODO:}else{// stop receive text thread.DWORD dwExitCode;GetExitCodeThread( m_pThreadRecv->m_hThread, &dwExitCode );AfxEndThread( dwExitCode, TRUE );}}要结束线程时,使⽤SetEvent,将信号量置为有信号。

mfc实现流程

mfc实现流程

mfc实现流程
MFC(Microsoft Foundation Class Library)是微软提供的一个类库,用于在Windows环境下开发基于C++的图形用户界面(GUI)应用程序。

使用MFC可以简化Windows应用程序的开发过程。

以下是使用MFC实现应用程序的基本流程:
1. 创建项目:在Visual Studio中创建一个新的MFC项目。

选择“File”菜单中的“New”->“Project”,然后选择“MFC Application”。

2. 设置项目属性:在项目创建后,需要设置一些属性,如应用程序类型(单文档或多文档)、使用的MFC版本等。

3. 设计界面:使用Visual Studio的设计器,在图形界面中添加需要的控件,如按钮、文本框等。

也可以手动编写代码来创建控件。

4. 编写代码:根据需要编写代码,包括处理用户输入、更新界面、访问数据库等。

MFC提供了许多类和函数,用于简化常见的编程任务。

5. 编译和运行:编译代码并运行应用程序,检查是否存在错误。

6. 调试:如果应用程序中存在错误,使用调试器来查找和修复问题。

7. 测试:进行彻底的测试,确保应用程序在不同情况下都能正常工作。

8. 部署:完成测试后,可以将应用程序部署到目标机器上。

以上是使用MFC实现应用程序的基本流程。

具体实现细节会根据具体需求和项目规模有所不同。

mfc运行流程

mfc运行流程

mfc运行流程
MFC程序的运行流程如下:
1.程序启动
程序启动时,首先会调用WinMain函数。

WinMain函数是MFC程序的入口函数,负责程序的初始化和运行。

2.程序初始化
在WinMain函数中,会调用CWinApp::InitInstance()函数进行程序的初始化。

CWinApp::InitInstance()函数负责注册窗口类、创建应用程序对象、创建窗口等工作。

3.窗口创建
在程序初始化完成后,会创建应用程序的窗口。

应用程序窗口是应用程序的入口,用户可以通过应用程序窗口与应用程序进行交互。

4.消息循环
在窗口创建完成后,会进入消息循环。

消息循环是MFC程序的核心,负责处理来自操作系统的消息。

5.程序退出
用户关闭应用程序时,会调用CWinApp::ExitInstance()函数退出程序。

CWinApp::ExitInstance()函数负责释放程序使用的资源。

第三章 MFC程序的工作流程和结构

第三章 MFC程序的工作流程和结构
Windows还提供一些宏来处理上述基本数据类型。 例如,LOBYTE和HIBYTE分别用来获取16位数值中 的低位和高位字节;LOWORD和HIWORD分别用来 获取32位数值中的低位字和高位字;MAKEWORD是 将两个16位无符号值结合成一个32位无符号值,等等。
杭州电子科技大学通信工程学院
3.2学习MFC的方法
unsigned long
unsigned long long long const char * char * void * long unsigned int unsigned short unsigned int
说明
布尔值 32位字符指针 8位无符号整数
用作颜色值的32位值
32位无符号整数,段地址和相关的偏移地址 32位带符号整数 作为参数传递给窗口过程或回调函数的32位值 指向字符串常量的32位指针 指向字符串的32位指针 指向未定义类型的32位指针 来自窗口过程或回调函数的32位返回值 32位无符号整数 16位无符号整数 当作参数传递给窗口过程或回调函数的32位值
首先要对Windows API有一定的了解,否则无法深 入学习MFC。至少要知道Windows对程序员来说 意味着什么,它能完成什么工作,它的一些常用数 据结构等。 其次,不要过分依赖于Wizards。Wizards能做许多 工作,但同时掩饰了太多的细节。应当看看 AppWizard和ClassWizard为你所做的工作。除非 你理解了生成的代码的含义,否则无法了解程序是 如何运行的。
MFC程序的 工作流程和结构
杭州电子科技大学通信工程学院
本章内容
•3.1 1Windows编程 •3.2学习MFC的方法 •3.3 MFC的应用程序框架 •3.4 ClassWizard •绍

MFC程序的启动过程与相关函数的执行顺序

MFC程序的启动过程与相关函数的执行顺序

MFC程序的启动过程与相关函数的执行顺序1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp 对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。

该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。

2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。

当theApp配置完成后,WinMain 登场,慢!细看程序,并没连到WinMain函数的代码啊!这个我也不知道,MFC早已准备好并由链接器直接加到应用程序代码中了,原来她在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。

那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。

_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){int nReturnCode = -1;CWinApp* pApp = AfxGetApp();AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);pApp->InitApplication();pApp->InitInstance()nReturnCode = pApp->Run();AfxWinTerm();return nReturnCode;}AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:CMyWinApp::InitApplication();CMyWinApp::InitInstance()CMyWinApp::Run();因而导致调用:CWinApp::InitApplication(); //因为 CMyWinApp 并没有改写 InitApplication CMyWinApp::InitInstance() //因为 CMyWinApp 改写了 InitInstanceCWinApp::Run(); //因为 CMyWinApp 并没有改写 Run用过SDK写程序的朋友,现在可能会发出会心的微笑。

T-MFC程序的执行流程

T-MFC程序的执行流程

1.2、theApp初始化机制引发的思考——代码抢先执行
1.2.1、正名---我所谓的代码抢先执行
我们暂且将主函数运行之前的代码称为抢先执行代码,具有一定意义的抢先执行代码(对于程序员来说)的执行暂且称为代码抢先执行。
1.2.2、使用theApp的初始化机制实现反调试示例
1.2.5、DLL_PROCESSS_ATTACH实现代码抢先执行的示例
1.2.6、基于高优先级的线程代码抢先执行
1.3、CWinApp构造函数与模块、线程状态信息
1.3.1、编码中的模块基址指明
1.3.2、PE中的模块基址及引发的问题
1.3.3、GetModuleHandle()函数的反汇编代码与缺陷弥补
00401320 |. FF15 088B4100 CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA
00401326 |. 3BF4 CMP ESI,ESP
00401328 |. E8 AB1C0000 CALL draw.__chkesp ; JMP 到 MSVCRTD._chkesp
1020AD2E 8339 00 CMP DWORD PTR DS:[ECX],0 ;地址中是否有内容
1020AD31 74 05 JE SHORT MSVCRTD.1020AD38
1020AD33 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] ; draw.$S374 在这里F4执行到此处
0040132D |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401330 |. 5F POP EDI

《面向对象程序设计》6章-12章问答题习题答案

《面向对象程序设计》6章-12章问答题习题答案

面向对象程序设计习题 面向对象程序设计习题


习 题7
(4) 映像模式是什么?它是如何定义的? 映像模式是什么?它是如何定义的?
映像模式定义逻辑坐标系的单位与设备坐标系的度量单位之间的 转换关系以及设备坐标系的X方向和 方向。其优点是, 方向和Y方向 转换关系以及设备坐标系的 方向和 方向。其优点是,程序 员可不必考虑输出设备的具体坐标系, 员可不必考虑输出设备的具体坐标系,而在一个统一的逻辑 坐标系中进行图形的绘制与操作。 坐标系中进行图形的绘制与操作。 设置当前设备环境的映像模式采用SetMapMode()函数,函数中 函数, 设置当前设备环境的映像模式采用 函数 的映像模式选择如下表: 的映像模式选择如下表:
面向对象程序设计习题 面向对象程序设计习题


6-2 简答题 (3) Windows应用程序中的消息传递是如何进行的? 应用程序中的消息传递是如何进行的? 应用程序中的消息传递是如何进行的
由Windows以及由其他应用程序向用户的应用程序发送的全部消息都 以及由其他应用程序向用户的应用程序发送的全部消息都 储存在消息队列中,等待调用。 程序以消息循环调用Windows消 储存在消息队列中,等待调用。SDK程序以消息循环调用 程序以消息循环调用 消 如下代码表示此循环一直运行到程序接受终止执行消息才停止。 息,如下代码表示此循环一直运行到程序接受终止执行消息才停止。 MSG Msg; … while (GetMessage (&Msg,NULL,0,0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } While循环内部 由循环的每次迭代调用Windows API函数 循环内部, 在While循环内部,由循环的每次迭代调用 函数 GetMessage (&Msg,NULL,0,0)以得到消息队列中的下一个消息,并把 以得到消息队列中的下一个消息, 以得到消息队列中的下一个消息 它存在特定的MSG结构体变量 结构体变量Msg中。TranslateMessage(&Msg)实现 它存在特定的 结构体变量 中 实现 键盘上某个键的翻译。 键盘上某个键的翻译。DispatchMessage(&Msg)函数向窗口的消息处 函数向窗口的消息处 理函数发送消息,调用相应的消息处理函数。 理函数发送消息,调用相应的消息处理函数。完成后进入下一个循环

MFC简介及第一个MFC程序

MFC简介及第一个MFC程序



4. 调用pApp->InitApplication,这是CWinApp的虚函数, 一般不需要改写;
22
简化的MFC程序启动过程-2/2

5. 调用 pApp->InitInstance,每个程序都必需改写这个函 数,进行应用程序初始化;在InitInstance函数中,先用 new构造一个CFrameWnd派生类对象,其构造函数又调 用Create,创建主窗口,MFC依次自动为应用程序注册

结束 删除CMainFrame
对象
退出Run 函数 删除theApp
25
程序开始 ① 初始化全局对象 theApp:CHelloApp ⑤
CHelloApp构造函数 ④ ② ③ CWinApp构造函数
AfxWinMain函数 { … CWinApp::InitApplication CHelloApp::InitInstance CWinApp::Run

一系列问题:
– WinMain在哪里? – RegisterClass,CreateWindow在哪? – 消息循环在哪? – 窗口过程函数如何执行?
16
简化的MFC程序类图
CObject CmdTarget CWinThread CWinApp CHelloApp CWnd CFrameWnd CMainFrame
Windows编程基础
东软人才实训中心 Copyright 2010 By Neusoft Group. All rights reserved
1
第二章 MFC简介及第一个MFC程序
本课程旨在向学员介绍: 1)了解MFC类库 2)理解第一个MFC程序执行过 程
时间:学时6 教学方法:讲授+课上 练习+课下作业

MFC操作步骤

MFC操作步骤

第一步:建MFC工程第二步:resource.h里填加#define ID_tian 32771第三步:~view.h 里PublicBOOL t; //如果左击鼠标,t为true,否则为fasleint n; //代表定点的个数CPoint p[100]; //定义点的对象数组(数据成员为点的x,y坐标)void boundaryfill4(int x,int y ,int FilledColor,int BoundaryColor); //实现种子四连通算法(这是填充算法中的一种)pretectedafx_msg void OnLButtonDown(UINT nFlags,CPoint point );afx_msg void OnRButtonDown(UINT nFlags,CPoint point );afx_msg void Ontian();第四步:~view.cpp在BEGIN_MESSAGE_MAP(CMyView, CView)下定义:ON_WM_LBUTTONDOWN()ON_WM_RBUTTONDOWN()ON_COMMAND(ID_tian, Ontian)ON_WM_CREATE()1、构造函数n=0;t=TRUE;2、修改成员函数OnDraw()pDC->TextOut(1,65," 先用左击画线,右击用于区域闭合");pDC->TextOut(1,88,"区域闭合后,点击菜单栏中的'填'!!");3、定义消息函数和成员函数#include <windows.h> // include all the windows headers#include <windowsx.h> // include useful macros#include <stdio.h>#include <stdlib.h>//#include"window.h"void CMyView::boundaryfill4(int x,int y ,int FilledColor,int BoundaryColor){}void CMyView::OnLButtonDown(UINT nFlags,CPoint point ){}}void CMyView::OnRButtonDown(UINT nFlags,CPoint point ){}void CMyView::Ontian(){ t=FALSE;MessageBox("请单击选取种子点") ;}。

MFC一些调用的步骤

MFC一些调用的步骤

MFC 一些调用的步骤 1,第一步,全局对象"theApp"的构造函数;2,真正的 main 函数隐藏在框架内,IDE 下 按 F11 可以进入 Main 函数3,跳转到 AfxWinMain 函数,看到调用了"InitInstace"虚函数,另外 CWinAPP 原来是从 CWinThread 派生的,是一个线程,以前没注意4,最后进入了 CWinThread::Run 函数,也就是进入了消息泵AfxMessageBox 引起死机 1,在 CListCtrl 右键菜单的执行中; 2,AfxMessageBox 的数据量 4K 左右; 结论: 不要用 AfxMessageBox 显示大量的数据设置树的节点高度Window 控件里面,树的节点高度是可以设置的,如下:tvis.hParent = hItem; tvis.itemex.mask = TVIF_TEXT|TVIF_INTEGRAL; tvis.itemex.pszText = TEXT("3 倍高度节点"); tvis.itemex.iIntegral = 3; m_wndTree.InsertItem(&tvis);iIntegral 表示是普通节点的 3 倍高度.一个小技巧,发现网上提及较少,故这里列出.VC++ 6.0 的小花招 Visual Studio 系列中产品中,Visual Studio 6.0 是最经典的一个版本,虽 然后来有 Visual Studio .NET 2003,以及 2005,也确实添加了很多让我觉得 激动的特性,但是从使用细节的细腻程度上来看,VS 6.0 无疑是最棒的.我 们一些同事甚至试图把 2005 的 C++编译器独立的拿到 Visual Studio 6.0 中 来用,也不愿意升级到.NET 上来用,可见其魅力.和 VS 6.0 这个产品的成熟相比,VC++ 6.0 的编译器的的确确相对来说有些糟 糕,其中最被诟病的是对模板技术支持很不好.下面我想做的一件事情,就是 向那些继续留恋 VC++ 6.0 的朋友,介绍一些小花招,来避开 VC++ 6.0 的一些 编译器缺陷.的作用域问题. 1)for (type var=expression;;) 中变量 var 的作用域问题.按照 C++标准,这里定义的变量 var 出了 for 循环应该被销毁.也就是说下面 这段代码是有效的:for (int i = 0; i < 100; ++i) func(); for (int i = 0; i < 100; ++i) func2();而下面这段代码应该编译不过:for (int i = 0; i < 100; ++i) { if (has_found_it()) { handle_find_result(); break; } } if (i == 100) do_not_found();然而 VC++ 6.0 对于第一段代码会报变量 i 重复定义错误,而第二段代码编译 通过.为了让 VC++ 6.0 的 for 语句看起来符合 C++标准,你可以这样做:#define for if (0); else for你会发现很有趣,这样 define 一下后,VC++ 6.0 的 for 语句完全符合 C++标 准了!而且由于编译器的优化,Release 版本不会增加任何额外的开销.喜欢"钻牛角尖"的朋友可能会说:嗯,不错的主意.但是——为什么不这样 做:#define for if (1) for嗯?看起来也可以.还是让我们看一个用例:if (cond) for (int i = 0; i < 100; ++i) func1(); else func2();进行宏代码展开后,成为:if (cond) if (1) for (int i = 0; i < 100; ++i) func1(); else func2();这个结果显然不能符合我们的原意.这里 func2();语句永远得不到执行机会.2)模板参数类型如果不出现在参数列表中,则不能作为返回值类型. 模板参数类型如果不出现在参数列表中,则不能作为返回值类型.由于编译器的缺陷,VC++ 6.0 不支持以下这种用法:template <class T1, class T2> T1 func(T2 arg) { T1 var; ... // 处理 var 过程 return var; }void test() { int result1 = func<int>(1); double result2 = func<double>(2); };很抱歉,这种用法 VC++ 6.0 不支持.让人恼火的是,VC++ 6.0 编译时不会提 示错误,但是生成的执行代码却很成问题.究其原因,是因为 VC++ 6.0 的 template 技术是在编译器的较高层次做的,真 正的编译器核心并不考虑模板.以上面的代码为例,对编译器核心来说,只是 有两个重载函数而已:int func(int arg); double func(int arg);如果是普通情况,只是返回值不同的函数,是不能同时存在的,编译器应该认 为这是一个错误. 但是很在模板情况下, 这两个函数被简单认为是同一个函数. 因为 VC++ 6.0 会为每个函数根据它的:1)所在的 namespace; 2)所在的类的类名(如果是成员函数); 3)函数名; 4)函数调用方式(cdecl,stdcall 还是 fastcall); 5)所有参数的类型; 而生成一个唯一标识该函数的函数名.这个过程叫 Name Mangling,是所有 C ++编译器都要进行的工作.而另一个背景是,很多 C++编译器生成的目标文件 (.obj 文件)有一些和模板相关的特殊信息,包括也标识了某个函数是否模 板函数.这是因为一个模板函数在多个源文件(.cpp 文件)中被调用的话, 这个模板函数就会在这些源文件编译生成的目标文件(.obj 文件)中都定义 (definition)一份.为了支持模板,link 程序显然必须知道这个函数是模 板函数,从而随意选择一个定义(丢弃其余的定义),而不是报符号重复定义 错误.因为函数名,参数列表等完全一致,所以这两个函数 Name Mangling 后生成的 名字是一样的,并且,它们都被标识为这是模板函数.从而,link 程序在工 作的时候,简单地将其中一个函数定义给抛弃了.那么,如果我们非要提供上述的 func 函数,怎么办?我们来点花招:template <class T1> class func { private: T1 var;public: template <class T2> func(T2 arg) {... // 处理 var 过程 } operator T1() const { return var; } };我们再来使用 func 这个"函数":void test() { int result1 = func<int>(1); double result2 = func<double>(2); };呵呵,你会发现,它还真象是你期望的正常工作.3)仿真 VC++提供的关键字__uuidof. VC++提供的关键字__uuidof. 提供的关键字__uuidof这个技巧不是针对 VC++ 6.0 缺陷的,而是针对 VC++扩展语法的.这个技巧的 来由,是为了某些希望有一天有可能要脱离 Visual C++环境进行开发的人员. 为了脱离 VC++,你需要谨慎使用它的所有扩展语法.例如本文讨论的__uuido f.我们先来看看一个例子:class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Clas s;struct __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BB")) Int erface;void test() { CLSID clsid = __uuidof(Class); IID iid = __uuidof(Interface); ... }这比起你以前定义 uuid 的方法简单多了吧?可惜,这样好用的东西,它只在 VC++中提供.不过没有关系,我们这里介绍一个技巧,可以让你在几乎所有 C ++编译器中都可以这样方便的使用__uuidof.这里没有说是所有,是因为我们 使用了模板特化技术,可能存在一些比较"古老"的 C++编译器,不支持该特 性.也许你已经迫不及待了.好,让我们来看看:#include <string> #include <cassert>inline STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz) { HRESULT hr; GUID guid; if (lpsz[0] == '{') { hr = CLSIDFromString(lpsz, &guid); }else{std::basic_string<OLECHAR> strGuid;strGuid.append(1, '{');strGuid.append(lpsz);strGuid.append(1, '}');hr = CLSIDFromString((LPOLESTR)strGuid.c_str(), &guid);}assert(hr == S_OK);return guid;}template <class Class>struct _UuidTraits {};#define _DEFINE_UUID(Class, uuid) \template<> \ struct _UuidTraits<Class>{ \static const GUID& Guid(){ \static GUID guid = GUIDFromString(L ## uuid); \return guid; \} \}#define __uuidof(Class) _UuidTraits<Class>::Guid()#define DEFINE_CLSID(Class, guid) \class Class; \_DEFINE_UUID(Class, guid)#define DEFINE_IID(Interface, iid) \struct Interface; \_DEFINE_UUID(Interface, iid)这样一来,就已经模拟出一个__uuidof关键字。

MFC程序运行机理

MFC程序运行机理

MFC程序的构造过程和运行机理初探我们先看一个例子:打开VC6.0,依次点击:文件(File)->新建(New)->工程(Project)->MFC AppWizard(exe)之后在右边输入路径和工程名称,这里暂定为:Test单击确定(OK)按钮进入下一页面,选择单文本(Single Document),然后点击完成。

好了,一个基于MFC的应用程序框架已经完成。

现在我们来编译看看:Ctrl+F5看到了效果图没?看到了对不?好了,下面我们一起来看看这个我们没有添加一行代码的MFC程序。

看到左边的资源管理框,选择“ClassView”标签,可以看到下面几个类:CAboutDlg,CMainFrame,CTestApp,CTestDoc,CTestView和一个全局变量:theApp我们就从这个全局变量说起。

看看这个MFC程序的执行过程。

我们知道创建一个完整的窗口需要经过下面四个操作步骤:1.设计一个窗口类;2.注册窗口类;3.创建窗口;4.显示及更新窗口。

1.设计一个窗口类我们知道全局对象的构造函数会在main 函数之前执行,那么这个全局类对象:theApp再main函数执行前就已经分配好了内存空间,由其定义class CTestApp : public CWinApp{....}可知,该全局类继承自CWinApp,那么可知在该对象创建的时候,CWinApp的构造函数会被调用。

之后,系统进入main函数,在MFC程序中,main函数是_tWinMain 函数,可以看看_tWinMain 的定义会发现,其实_tWinMain 就是WinMain。

_tWinMain 函数在Microsoft Visual Studio\VC98\MFC\SRC\APPMODUL.CPPextern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}其实里面就一行代码,又调用了AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) 函数,AfxWinMain 函数在Microsoft Visual Studio\VC98\MFC\SRC\WINMAIN.CPP 文件中在AfxWinMain 函数里,先声明了一个CWinThread 类对象pThreadCWinThread* pThread = AfxGetThread();然后调用pThread->InitInstance() 函数,这个函数很重要,我们看看它的定义:在CWinThread类的头文件AFXWIN.H 中,可以发现如下代码,virtual BOOL InitInstance();这说明InitInstance() 函数是个虚函数,这里我们可以看看继承关系:class CTestApp : public CWinApp{....}class CWinApp : public CWinThread{....}这样我们就可以明白CTestApp其实继承自CWinThread,好的,明白这一点后,我们再看看CWinApp的构造函数:CWinApp::CWinApp(LPCTSTR lpszAppName){.....pThreadState->m_pCurrentWinThread = this;.....}这里我们看到了上面的一行代码,这里的这个this指针到底指向谁呢?根据虚拟函数的特性和继承性原理我们知道它指向的是CWinApp的派生类CTestApp的对象,至此我们明白在AfxWinMain 函数里,CWinThread* pThread = AfxGetThread();CWinApp* pApp = AfxGetApp();表明pApp、pThread 实际指向的都是CTestApp 类对象,那么在后面的pThread->InitInstance() 函数实际调用的是CTestApp 类的成员函数InitInstance() 。

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

MFC程序的启动过程与相关函数执行顺序原文地址:/chuntian1919/blog/item/f5b7f5fd898e2c1408244d3c.html了解MFC程序的启动过程,对于初学者来讲,了学习MFC很有帮助;对于不常用VC 的人来说,过一段时间就会忘记。

还是来记下来,方便以后查阅。

1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp 对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。

该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。

2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。

当theApp配置完成后,WinMain 登场,慢!细看程序,并没连到WinMain函数的代码啊!这个我也不知道,MFC早已准备好并由链接器直接加到应用程序代码中了,原来她在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。

那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。

_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){int nReturnCode = -1;CWinApp* pApp = AfxGetApp();AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);pApp->InitApplication();pApp->InitInstance()nReturnCode = pApp->Run();AfxWinTerm();return nReturnCode;}AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:CMyWinApp::InitApplication();CMyWinApp::InitInstance()CMyWinApp::Run();因而导致调用:CWinApp::InitApplication(); //因为CMyWinApp 并没有改写InitApplicationCMyWinApp::InitInstance() //因为CMyWinApp 改写了InitInstanceCWinApp::Run(); //因为CMyWinApp 并没有改写Run用过SDK写程序的朋友,现在可能会发出会心的微笑。

3、AfxWinInit——AFX内部初始化操作AfxWinInit是继CWinApp构造函数之后的第一个操作,主要做的是AFX内部初始化操作,该函数定义于APPINIT.CPP第24行,这里就不掏出来了,你自己搜出来啃吧!4、执行CWinApp::InitApplicationAfxWinInit之后的操作是pApp->InitApplication,我们已知道pApp指向CMyWinApp 对象,当调用:pApp->InitApplication();相当于调用:CMyWinApp::InitApplication();但是你要知道,CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数,我们并没有改写它(大部分情况下不需改写它),所以上述操作相当于调用:CWinApp::InitApplication();此函数定义于APPCORE.CPP第125行,你自己搜出来看吧!我就不搬出来了,里面的操作都是MFC为了内部管理而做的(其实我也看不懂,知道有这回事就好了)。

5、执行CWinApp::InitInstance继InitApplication函数之后,AfxWinMain调用pApp->InitInstance。

当程序调用:pApp->InitInstance();相当于调用:CMyWinApp::InitInstance();但是你要知道,CMyWinApp继承自CWinApp,而InitInstance又是CWinApp的一个虚拟函数。

由于我们改写了它,所以上述操作就是调用我们自己(CMyWinApp)的这个InitInstance函数。

6、CFrameWnd::Create产生主窗口(并先注册窗口类)现在已经来到CWinApp::InitInstance了,该函数先new一个CMyFrameWnd对象,从而产生主窗口。

在创建CMyFrameWnd对之前,要先执行构造函数CMyFrameWnd::CMyFrameWnd(),该函数用Create函数产生窗口:CMyFrameWnd::CMyFrameWnd(){Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu");}其中Create是CFrameWnd的成员函数,它将产生一个窗口,用过SDK编程序的朋友都知道,要创建主窗口时要先注册一个窗口类,规定窗口的属性等,但,这里使用哪一个窗口类呢?Create函数第一个参数(其它参数请参考MSDN或《深出浅出MFC》详解)指定窗口类设为NULL又是什么意思啊?意思是要以MFC内建的空中类产生一个标准的外框窗口,但,我们的程序一般都没有注册任何窗口类呀!噢,Create函数在产生窗口之前会引发窗口类的注册操作。

让我们先挖出Create函数都做了些什么操作,Create函数定义于WINFRM.CPP的第538行(在此我就不把代码Copy过来了,你自己打开出来看吧),函数在562行调用CreateEx 函数,由于CreateEx是CWnd的成员函数,而CFrameWnd是从CWnd继而来,故将调用CWnd::CreateEx。

此函数定义于WINCORE.CPP第665行,下面是部分代码:BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) {// allow modification of several common create parametersCREATESTRUCT cs;cs.dwExStyle = dwExStyle;cs.lpszClass = lpszClassName;cs.lpszName = lpszWindowName;cs.style = dwStyle;cs.x = x;cs.y = y;cs.cx = nWidth;cs.cy = nHeight;cs.hwndParent = hWndParent;cs.hMenu = nIDorHMenu;cs.hInstance = AfxGetInstanceHandle();cs.lpCreateParams = lpParam;if(PreCreateWindow(cs)){PostNcDestroy();return FALSE;}AfxHookWindowCreate(this);HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);...}用过SDK编程序的朋友,看到上面代码应该有一点感觉了吧,函数中调用的PreCreateWindows是虚拟函数,在CWnd和CFrameWnd之中都有定义。

由于this指针所指对象的缘故,这里应该调用的是CFrameWnd::PreCreateWindow。

该函数定义于WINFRM.CPP第521行,以下是部分代码:BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs){if (cs.lpszClass == NULL){VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background }...}其中AfxDeferRegisterClass是一个定义于AFXIMPL.H中的宏。

该宏如下:#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) 注:这里有宏和《深入浅出MFC》的不一样,以上代码是从Visual C++ 6.0摘取。

AfxEndDeferRegisterClass定义于WINCORE.CPP第3619行,该函数很复杂,主要是注册五个窗口类(哇!终于看到窗口类了,怎么用5个呢?我还不清楚),不同类的PreCreateWindow成员函数都是在窗口产生之前一刻被调用,准备用来注册窗口类。

相关文档
最新文档