1 VC6代码格式化:selectionformat

定制→编辑→lelectionformat:alt+F8、ctrl+alt+A

2 完全取词功能

在代码编辑区中将光标定位在某个类的任意方法上,单击鼠标右键,在弹出的快捷菜单中选择“List Members”命令或以显示出方法所在类的所有成员信息。

如果出现以上功能不好使的情况,可以关闭当前的工程,然后在工程目录下删除扩展名为“.ncb”的文件,然后重新打开工程,Visual C++会 重建一个“.ncb”文件,此时完全取词功能将恢复正常。

VC++ Intellisense Database (.ncb)

Visual Assist X插件。

如果删掉了dsw文件,怎样手动链接各.cpp、.h文件?

1 新建两个文件夹:source files、header files;

2 将.h文件加入到header files

3 将.cpp、.rc文件加入到source files

4 如果有windows.h头文件,VC→工程→选项→连接:最下面的文本框:将其中的subsystem:console改为subsystem:windows

运算符重载时VC++报错

对于VC++报错:fatal error C1001: INTERNAL COMPILER ERROR

有以下两种可能:

1、运算符重载时遇到以上错误代码

将#include<iostream> 改成 #include<iostream.h>

然后去掉 using namespace std;

或者你要前向声明类,然后声明友元函数(注意不要加friend),也可以顺利通过编译!

或者你打上vc6.0的sp6补丁就可以了!

2、如果你在用 VC6 编一个规模较大的工程,如果你在用 VC6 编译一个用到了模板的工程,那恭喜你,这个错误会时不时冒地出来和你打招呼,搞得你手足无措。

字符编码的问题

编辑器的编码,工程的编码选择、环境(系统)的编码。还有字节序的问题。

#ifdef UNICODE
typedef wchar_t TCHAR
#else
typedef char TCHAR

同时,为了简便操作,还定义了一个更简短的宏 _T / _TEXT,来表示一个通用字符串

#define _T(x) __T(x)
UNICODE: #define __T(x) L##x
ASCII: #define __T(x) x

Class CString 类模板为基础CStringT 类。 CString 是typedef的CStringT。 更准确地说CString是typedef的显式专用化的CStringT,这是 使用类模板定义的类的常用方法。 同样定义的类是CStringA和CStringW。

在windows平台下,ms的编译器(也就是vc带的那个)在 Debug 模式下,会把未初始化的栈内存全部填成 0xcc,用字符串来看就是”烫烫烫烫 烫烫烫”,未初始化的堆内存全部填成0xcd,字符串看就是“屯屯屯屯屯屯屯屯”。

Serialize

打开和保存文档时,系统都会自动调用Serialize函数。用户处理的数据往往需要存盘作永久备份。将文档类中的数据成员变量的值保存在磁盘 文件中,或者将存储的文档文件中的数据读取到相应的成员变量中。这个过程称为序列化(Serialize)。

Serialization是指将对象内容写到文件中,或从文件中读出。如此一来对象的生命就可以在程序结束之后还延续下去,而在程序重新激活之后 ,再被读入。这样的对象可说是"persistent"(永续存在)。

如果按下【File/Open】,Application Framework 会激活对话框让你指定文件名,然后自动调用CMyDoc::Serialize 读档。Application Framework 还会调用CMyView::OnDraw,把资料显示出来。

如果屏幕状态改变, 产生了WM_PAINT , Framework 会自动调用你的CMyView::OnDraw,传一个Display DC 让你重新绘制窗口内容。

实际上并没有数据写到显示屏上,所有到显示屏的输出都是图形,不管是直线,圆,还是文本。

如果按下【File/Print...】,Framework 会自动调用你的CMyView::OnDraw,这次传进去的是个Printer DC,因此绘图动作的输出对象就成了 打印机。

对话框的数据交换

程序运行界面中,用户往往会改变控件的属性,例如,在编辑框中输入字符串,或者改变组合框的选中项,又或者改变复选框的选中状态等。 控件的属性改变后MFC会相应修改控件关联变量的值。这种同步的改变是通过MFC为对话框类自动生成的成员函数DoDataExchange()来实现的, 这也叫做对话框的数据交换和检验机制。

这种数据交换机制中,DoDataExchange()并不是被自动调用的,而是需要我们在程序中调用CDialogEx::UpdateData()函数,由UpdateData()函 数再去自动调用DoDataExchange()的。

CDialogEx::UpdateData()函数的原型为:
BOOL UpdateData(BOOL bSaveAndValidate = TRUE);

参数:bSaveAndValidate用于指示数据传输的方向,TRUE表示从控件传给变量,FALSE表示从变量传给控件。默认值是TRUE,即从控件传给变量 。

返回值:CDialogEx::UpdateData()函数的返回值表示操作是否成功,成功则返回TRUE,否则返回FALSE。

MFC程序的生与死

1 程序的诞生

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

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

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

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

1.5 CMyWinApp::InitInstance 'new' 了一个CMyFrameWnd 对象。

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

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

1.8 执行UpdateWindow,于是发出WM_PAINT。

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

2 程序开始运作

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

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

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

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

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

3 程序的死亡

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

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

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

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

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

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

3.7 最后回到AfxWinMain,执行AfxWinTerm,结束程序。Sub 格式化文本框()

MFC与API

对于绘图、事件响应,C本身都没有对应库,一般都由OS提供API。

操作系统会提供用于某种语言编程的API接口,编程就要使用这些API函数进行,包括绘制控件、事件响应。

SDK 程序只要包含windows.h就好,所有API的函数声明、消息定义、常数定义、宏定义、都在windows.h档中。除非程序另调用了操作系统 提供的新模块(如CommDlg、ToolHelp、DDEML...),才需要再各别包含对应的.h档。

windows.h过去是一个巨大文件,大约在5000行上下。现在已拆分内容为数十个较小的.h档,再由windows.h包含进来。也就是说它变成一个"Master included file for Windows applications"。

任何Windows应用程序与Windows本身之间的所有通信,都要使用Windows应用程序编程接口,也称为Windows API。该接口由多达数百个函数组成,它们是Windows操作系统提供的标准函数,可以提供应用程序与Windows相互通信的方法。

编写某种操作系统的应用程序,一般需要调用该操作系统为某种编程语言提供的API函数。这样,应用程序只需与该操作系统交互,由该操作系统与硬件交互。

Windows API的数据类型为了增加程序的可读性和可移植性,使用typedef重新定义了数据类型或复合数据类型。

句柄也是用typedef对结构体的重新定义。

句柄是使用了宏定义,指向一个被隐藏了结构的数据区域的指针。

Windows数据类型是对C数据类型的重定义,是为了增强程序的可读性、为了便于移植。

面向对象的一个重要特点,不但是数据与处理这些数据的函数的关联性很强,同时,函数之间也可以形成逻辑关系。前者是封装,后者是继承与多态。

Windows API是在C还是主要通用语言的年代开发的,很久以后C++才出现,因此经常用在Windows和应用程序之间传递数据的是结构而不是类。

Windows API覆盖了Windows与应用程序之间通信的所有方面。VC以面向对象的方式重新组织了这些API函数,并提供了在C++中使用该接口更容易的方法,且带有更多的默认功能,也就是MFC。

MFC帮助我们把这些浩繁的APIs,利用对象导向的原理,逻辑地组织起来,使它们具备抽象化、封装化、继承性、多态性、模块化的性质。

Windows API有超过1000个函数,这些函数的类别不是特别清晰。MFC用C++的类进行封装,相同类别的函数封装到相同的类内,相互的关系便变得清晰起来。这就是类类型的思想,将数据和操作这些数据的函数聚合起来,但通过继承可以共享数据和代码。通过访问控制可以实现数据隐藏。

1989年微软公司成立Application Framework技术团队,名为AFX小组,用以开发C++对象导向工具给Windows应用程序开发人员使用。AFX的"X" 其实没有什么意义,只是为了凑成一个响亮好念的名字。

类封装的是数据和算法,且相互之间有了联系(继承与多态),这是没有联系的全局函数所不能比拟的。

MFC是对win32的封装,使用win32编程方法,写了一个又一个类,让我们不用再重复大量劳动。但毕竟是封装,所以不可能完全实现win32所有功能。用着虽然方便,但距离细节毕竟远了,在个性、特殊化方面还有差距。

MFC中除了MFC类(封装API)以外,还包括部分宏和全局成员,这些都不属于类的成员,比如全局函数和全局变量。

C++ 并不是纯种的对象导向语言(SmallTalk 和Java 才是)。所以,MFC之中得以存在有不属于任何类别的全域函数,它们统统在函数名称开头冠以Afx。

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

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

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

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

新建console程序时,可以选择创建一个支持MFC(如支持CString类型)的程序,在工程中会增加一个stdafx的.h和.cpp文件,包含了以下头文件。

#include <afx.h>
#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdtctl.h>       // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>         // MFC support for Windows Common Controls#include <iostream>

所以,如果你创建了一个console文件后,如果当时没有选择MFC支持,只需加入上述头文件即可以得到MFC支持。

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

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

一般习惯为每个类别准备一个.h(头文件)和一个.cpp(实现)。

MFC已经把程序大架构完成了,模块与模块间的消息流动路径以及各函数的功能职司都已确定好(这是MFC 之所以够格称为一个Framework的原因),所以我们写程序的焦点就放在那些必须改写的虚拟函数身上即可。

GUI的资源:用一个结构体描述资源的属性,具体的资源所需内存用一个指针指向。这样的一个结构体指针就是句柄,其与MFC类可以相互转换 。

Application Framework 带来的革命精神是,程序模型已经存在,程序员只要依个人需求加料就好:在衍生类别中改写虚拟函数,或在衍生类 别中加上新的成员函数。这很像你在火锅拼盘中依个人口味加盐添醋。

C#这些年也有所涉猎,但主要用来写WEB程序,桌面程序也写过,各种类封装的非常多,开发效率高,但是有时感觉封装过度,而且让使用者远 离事情真相,有一种隔靴搔痒的感觉,对于我这种操作系统都想自己编译完跟进去调试的人来说,感觉超级别扭,另外一个就是运行期即时编 译的方式也感觉很不爽,还有就是安全性,不混淆的代码用工具一分钟就能把源码逆出来,即便是混淆后的,如果抽一天时间学习以下IL,也 是轻而易举的事情,凡此种种吧,.net基本上也是能不用则不用。

我们学习XX语言XX框架XX库实际上是为了解决具体问题的,而解决问题的能力就如同编程中的数据结构和算法一样是通用的东西,也应该成为 我们特别关注的一点。