为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

《深入浅出MFC》学习笔记

2017-09-27 13页 doc 41KB 3阅读

用户头像

is_014457

暂无简介

举报
《深入浅出MFC》学习笔记《深入浅出MFC》学习笔记 -——《深入浅出MFC》学习笔记之一 作者:XGM RRC.BIT 记于2001-8-10 龚建伟评:这篇学习笔记虽然不是系统的阐述某个问题,但读来让人感到收获不小,无论你是老鸟还是菜鸟,都会认同的。我希望XGM能够继续写下去,看了《深入浅出MFC》再来看这些笔记,也有温故知新之感 俟杰先生的《深入浅出MFC》是一本好书,本人是作为有一定C++基础知识并对VC有一点感性认识的VC初学者来接触这本书的。应该说这本书并不真正适合像我这样的初学者,但通读完该书,还是有一些收获的,现只整理其中的一部分...
《深入浅出MFC》学习笔记
《深入浅出MFC》学习笔记 -——《深入浅出MFC》学习笔记之一 作者:XGM RRC.BIT 记于2001-8-10 龚建伟评:这篇学习笔记虽然不是系统的阐述某个问题,但读来让人感到收获不小,无论你是老鸟还是菜鸟,都会认同的。我希望XGM能够继续写下去,看了《深入浅出MFC》再来看这些笔记,也有温故知新之感 俟杰先生的《深入浅出MFC》是一本好书,本人是作为有一定C++基础知识并对VC有一点感性认识的VC初学者来接触这本书的。应该说这本书并不真正适合像我这样的初学者,但通读完该书,还是有一些收获的,现只整理其中的一部分,作为我的一个学习笔记吧。 1. 安装VC++,为什么要先安装Internet Explorer,(是不是很多老鸟也 不知道啊,侯俊杰先生的宗旨就是知其然,还要知其所以然, 5555555555 „„„„) 因为微软的所有Visual Tools(包括Visual C++、Visual Basic、Visual FoxPro、Visual J++、Visual InterDev等)都集中由所谓的Visual Studio 管理,而这些工具有一个极大的目标,就是要协助开发Internet应用软 件,所以它们希望能够和IE有所搭配。 2. SDK:Software Development Kit 原指软件开发工具,但现在已经变成 了一个专有名词,凡以Windows raw API撰写的程序通常也称为SDK程 序。也有人把Windows API称为SDK API。 3. 不同种类之对象的构造函数(对象诞生后第一个执行并且是自动执行的 函数)及析构函数(对象行将毁灭,但未毁灭之前一刻,最后执行并且 自动执行的函数)执行时机对比如下: 全局对象 局部对象 静态对象 以new产生的对象 程序一开 始就执行构造函(比程序对象诞生时执行 数 进入点更 早) 程序将结程序流程束时执行,程序即将离开该对析构函但比全局对象被delete时结束时执象的存活数 对象的析执行 行 范围时执构函数早行 一步进行。 4. C++并不是纯种的面向对象语言(SmallTalk 和 Java才是)。所以,MFC之中得以存在有不属于任何类的全局函数,它们统统在函数名称开头冠以Afx(x并没有什么意思,只是为了凑成一个响亮的名字,Af即Application Framework) 下面是常见的Afx全局函数: AfxBeginThread:开始一个新的线程 AfxEndThread:结束一个旧的线程 AfxFormatString1:类似printf一般地将字符串格式化 AfxFormatString2:类似printf一般地将字符串格式化 AfxMessageBox:类似Windows API 函数 MessageBox AfxOuputDebugString:将字符串输往除错装置 AfxGetApp:获得application object (CwinApp派生对象)的指针 AfxGetMainWnd:获得程序主窗口的指针 AfxGetInstance:获得程序的instance handle 5. MFC数据类型 下面这些是和Win32程序共同使用的数据类型 BOOL:布尔值,取值为TRUE or FALSE BSTR:32-bit 字符指针 BYTE:8-bit整数,未带正负号 COLORREF:32-bit数值,代表一个颜色值 DWORD:32-bit整数,未带正负号 LONG:32-bit整数,带正负号 LPARAM:32-bit整数,作为窗口函数或callback函数的一个参数 LPCSTR:32-bit指针,指向一个常数字符串 LPSTR:32-bit指针,指向一个字符串 LPCTSTR:32-bit指针,指向一个常数字符串,此字符串可以移植到Unicode和DBCS LPTSTR:32-bit指针,指向一个字符串,此字符串可以移植到Unicode和DBCS LPVOID:32-bit指针,指向一个未指定类型的数据 LPRESULT:32-bit数值,作为窗口函数或callback函数的返回值 UINT:在Win16中是一个16-bit 未带正负号整数,在Win32中是一个32-bit 未带 正负号整数, WNDPROC:32-bit指针,指向一个窗口函数 WORD:16-bit 整数 ,未带正负号 WPARAM:窗口函数或callback函数的一个参数,在Win16中是16-bit,在Win32中是32-bit 下面这些是MFC独特的数据类型 POSITION:一个数值,代表collection对象(例如数组或链表)中的元 素位置,常 用于MFC collection classes(即数据处理类,如CArray) LPCRECT:32-bit指针,指向一个不变的RECT结构 6. 奇怪的窗口类名称Afx:b:14ae:6:3e8f 用Spy++(VC++所附的一个工具)观察窗口类的名称时,会发现窗口 类名称变成像Afx:b:14ae:6:3e8f这副奇怪的模样, 原来是Application Framework 把窗口类的名称转换为Afx:: x :y :z : w的类型,成为独一无二的窗口类型名称: x:窗口风格的hex值 y:窗口鼠标光标的hex值 z:窗口后台颜色的hex值 w:窗口图标的hex值 7. Serializable 的必要条件 让一个对象有Serializable能力,它必须派生自一个Serializable类,一 个类要成为Serializable,必须有下列五大条件: (1)从Cobject派生下来,如此一来,可保有RTTI、动态生成等机能 (2)类的声明部分必须有DECLARE_SERIAL宏,此宏需要一个参数:类 名称 (3)类的实作部分必须有IMPLEMENT_SERIAL宏,此宏需要三个参数: 一是类名称,二是基类名称,三是 schema no. (4)改写Serialize虚拟函数,使它能够适当地把类的成员变量写入档 案中 (5)为此类加上一个default构造函数(也就是无参数之构造函数), 这个条件常为人所忽略,但它是必要的,因为若一个对象来自档案, MFC必须先动态生成它,而且在没有任何参数的情况下调用其构造函 数,然后才从档案中读出对象数据。 唉,好东东实在太多了,比如对MFC六大关键技术之仿真,三大宏的内部揭 密等等(咦,我不是在推销这本书吧,呵呵)感兴趣的话请看看这本书吧,可以 找我借哦,所谓“书非借不能读也”。呵呵„„„ MFC程序的来龙去脉 -《深入浅出MFC》学习笔记之二 作者:XGM 2001-8-14 MFC程序也是Windows程序,所以它也有一个WinMain,但是我们在程序中看不到它的踪影。实际上,在程序进入点之前,有一个(而且只有一个)全局对象(在Hello程序中名为theApp),这是所谓的application object,当操作系统将程序加载并激活时,这个全局对象获得配置,其构造函数会先执行,比WinMain更早。 书中所举Hello程序,是一个简单的MFC程序,其主体在于WinMain和WndProc,而这两个部分其实都有相当程度的不变性。MFC就是把有着相当固定行为的WinMain内部操作封装在CWinApp中;把有着相当固定行为的WndProc内部操作封装在CFrameWnd中。也就是说,CWinApp代表程序本体,CFrameWnd代表一个主框窗口 虽然WinMain和WndProc内部操作有相当程度的不变性,但面对不同应用程序也需有变化,所以必须以这两个类为基础,派生自己的类,并改写其中一部分成员函数。 CWinApp----取代WinMain的地位 传统上SDK程序的WinMain所完成的工作现由CWinApp的三个函数完成: virtual BOOL InitApplication( ); virtual BOOL InitInstance( ); virtual BOOL Run( ); CFrameWnd-----取代WndProc的地位 CFrameWnd主要用来掌握一个窗口 引爆器------Application object 当执行Hello程序时,这个全局对象产生,于是构造函数(见APPCORE.CPP)执行起来,CWinApp之中的成员变量将因为这个全局对象的诞生而获得配置与初 值,配置完成后,WinMain(MFC早已准备好,并由链接器直接加到应用程序中去的)登场。 AfxWinInit:是继CWinApp构造函数之后的第一个操作; 此后的操作是pApp->InitApplication(其中的pApp指向CMyWinApp对象,即本例中的theApp),因为CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数,我们没有改写它(大部分情况下也不需要改它),所以上述操作相当于调用CWinApp::InitApplication。此程序的代码出现在APPCORE.CPP中; 继InitApplication之后,AfxWinMain调用pApp->InitInstance,InitInstance是CWinApp的一个虚拟函数(应用程序一定要改写这个函数,因为它在CWinApp中是个空函数,没有任何默任操作),我们改写了它,所以上述操作就是调有我们自己的这个InitInstance函数,我们将在该处展开我们的主窗口生命。 CMyWinApp::InitInstance一开始new了一个CMyFrameWnd对象,new会引发构造函数CmyFrameWnd::CMyFrameWnd,其中调用了CFrameWnd的成员函数Create,它将产生一个窗口。 Create函数共八个参数,第一个,指定WNDCLASS窗口类,如果放置NULL,表示要以MFC内建的窗口类产生一个标准的外框窗口(Create函数在产生窗口之前会引发窗口类的注册操作,下一段讲述这一内容);第二个,指定窗口标题;第三个,指定窗口风格,默认是WS-OVERLAPPEDWINDOW,如果你不想要窗口右上角的极大极小钮,可以改成 WS-OVERLAPPED|WS-CAPTION|WS-SYSMENU|WS-THICKFRAME|WS-MINIMIZEBOX|WS-MAXIMIZEBOX,如果希望有垂直滚动条,再加上WS-VSCROLL;第四个参数,指定窗口的位置与大小,默认值rectDefault ;第五个,指定父窗口,第六个指定菜单;第七个,为扩充风格,唯有以:CreateWindowEx(而非:CreateWindow)函数才能完成,事实上,CFrameWnd:Create最终调用的正是:CreateWindowEx;第八个,是一个指向CCreateContext结构的指针,framework利用它,在具备Document/View结构的程序中初始化外框窗口,默认值NULL CFrameWnd:Create在函数中调用CreateEx(CWnd有这个成员函数,但其派生类CFrameWnd并没有,所以这里调用的实际上是CWnd:CreateEx);后者又调用PreCreateWindow虚拟函数(它在CWnd及其派生类CFrameWnd都有定义,所以实际上调用的是CFrameWnd::PreCreateWindow),这个函数调用了AfxDeferRegisterClass宏,它表示如果变量afxRegisteredClass的值显示系统已经注册了fClass 这种窗口类,MFC啥也不做,否则就调用 AfxEndDeferRegisterClass(fClass){它调用两个函数完成实际的窗口类注册操作,一个是RegisterWithIcon,一个是AfxRegisterClass},准备注册之。 窗口显示与更新 CMyFrameWnd::CMyFrameWnd结束后,窗口已经诞生出来;程序又回到 CMyWinApp::InitInstance,于是调用ShowWindow函数令窗口显示出来,并调用UpdateWindow函数令Hello程序送出WM-PAINT CWinApp::Run----程序生命的活水源头 Run又是CWinApp的一个虚拟函数,我们没有改写它(大部分情况下也不需要改它),所以上述操作相当于调用CWinApp::Run WinMain已由MFC提供,窗口类已由MFC注册完成,连窗口函数也都由MFC提供 把消息与处理函数连接在一起:Message Map机制 MFC提供给应用程序使用的“很方便的接口”是两组宏,以Hello为例,第一个操作是在Hello.h的CMyFrameWnd加上DECLARE-MESSAGE-MAP;第二个操作是在Hello.cpp的任何位置(当然不能在函数内)使用宏 BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_COMMAND(IDM_ABOUT, OnAbout) ON_WM_PAINT() END_MESSAGE_MAP() 来龙去脉总整理 程序的诞生 Application object 产生, 内存于是获得配置,初值亦设立了。 AfxWinMain执行AfxWinInit,后者又调有AfxInitThread,把消息队列尽量 加 大到96 AfxWinMain执行InitApplication。这是CWinApp的虚拟函数,我们通常不改 写它 AfxWinMain执行InitInstance。这是CWinApp的虚拟函数,我们必须改写它 CMyWinApp::InitInstance “new”了一个CMyFrameWnd对象 CmyFrameWnd构造函数调用Create,产生主窗口。我们在Create参数中指定 的窗口类是NULL,于是MFC根据窗口种类,自行为我们注册一个名为 “AfxFrameOrView42d”的窗口类。 回到InitInstance中继续执行ShowWindow,显示窗口 执行UpdateWindow,于是发出WM-PAINT 回到AfxWinMain,执行Run,进入消息循环。 程序开始运行: 程序获得WM-PAINT消息(由CWinApp::Run中的::GetMessage循环) WM-PAINT经由::DispatchMessage送到窗口函数CWnd::DefWindowProc中。 CWnd::DefWindowProc将消息传递到消息映射表格 传递过程中发现有相符项目,于是调用项目中对应的函数。此函数是利用 BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的宏设立起来的。 标准消息的处理程序亦有标准命名,例如WM-PAINT必由OnPaint处理 程序的死亡: 使用者单击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,结束程序 附Hello程序部分代码: Hello.cpp #include "Stdafx.h" #include "Hello.h" #include "Resource.h" CMyWinApp theApp; // application object //------------------------------------------------------------------- - // CMyWinApp's member //------------------------------------------------------------------- - BOOL CMyWinApp::InitInstance() { m_pMainWnd = new CMyFrameWnd(); m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } //------------------------------------------------------------------- - // CMyWinApp's member //------------------------------------------------------------------- - BOOL CMyWinApp::OnIdle(LONG lCount) { CMyFrameWnd* pWnd = (CMyFrameWnd*)m_pMainWnd; pWnd->IdleTimeHandler(lCount); return TRUE; } //------------------------------------------------------------------- - // CMyFrameWnd's member //------------------------------------------------------------------- - CMyFrameWnd::CMyFrameWnd() { Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu"); } //------------------------------------------------------------------- - BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_COMMAND(IDM_ABOUT, OnAbout) ON_WM_PAINT() END_MESSAGE_MAP() //------------------------------------------------------------------- - void CMyFrameWnd::OnPaint() { CPaintDC dc(this); CRect rect; GetClientRect(rect); dc.SetTextAlign(TA_BOTTOM | TA_CENTER); ::LineDDA(rect.right/2, 0, rect.right/2, rect.bottom/2, (LINEDDAPROC) LineDDACallback, (LPARAM) (LPVOID) &dc); } //------------------------------------------------------------------- - VOID CALLBACK CMyFrameWnd::LineDDACallback(int x, int y, LPARAM lpdc) { static char szText[] = "Hello, MFC"; ((CDC*)lpdc)->TextOut(x, y, szText, sizeof(szText)-1); for(int i=1; i<50000; i++); } //------------------------------------------------------------------- - void CMyFrameWnd::OnAbout() { CDialog about("AboutBox", this); // "AboutBox" about.DoModal(); } //------------------------------------------------------------------- - void CMyFrameWnd::IdleTimeHandler(LONG lCount) { CString str; CRect rect(10,10,200,30); CDC* pDC = new CClientDC(this); str.Format("%010d", lCount); pDC->DrawText(str, &rect, DT_LEFT | DT_TOP); } Hello.h class CMyWinApp : public CWinApp { public: virtual BOOL InitInstance(); // virtual BOOL OnIdle(LONG lCount); // OnIdle e }; //------------------------------------------------------------------- - class CMyFrameWnd : public CFrameWnd { public: CMyFrameWnd(); // constructor afx_msg void OnPaint(); // for WM_PAINT afx_msg void OnAbout(); // for WM_COMMAND (IDM_ABOUT) void IdleTimeHandler(LONG lCount); // we want it call by CMyWinApp::OnIdle private: DECLARE_MESSAGE_MAP() // Declare Message Map static VOID CALLBACK LineDDACallback(int,int,LPARAM); // };
/
本文档为【《深入浅出MFC》学习笔记】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索