【滴水基础】5.MFC(3)
第十:GDI基础概念和MFC的CDC类
#GDI图形设备(Graphics Device InterFace)
---和Win32Api类似,为应用程序提供了可调用的多种服务,这些服务构成了强大、通用的图形编程语言
#DC图形描述表(同时表示设备上下文)
---Windows程序在屏幕、打印机、其它输出设备上画图时,并不是将像素直接输出到设备上
---而是将图先绘制到设备描述表(内存设备dc)表示的逻辑意义上的显示平面上去
---它是Windows中的一种数据结构,包含了GDI需要的所有有关于显示平面情况的描述
---早期的图形开发,是针对具体的设备开发(如:根据打印机厂家提供的不同接口开发不同的代码),需要适配不同的显卡,造成开发者困难
---Windows通过驱动管理,将设备接口细节隐藏在OS内部,我们只需要针对一个:公有的虚拟设备DC
#MFC不同场景下的DC类
---MFC的CDC类,将DC和HDC(句柄:可以操作所有DC有关的GDI函数)的GDI函数封装到了一起,派生了四个不同场景的DC类,以下是常用的3个
---注意:OnPaint是ON_WM_PAINT消息的响应函数,当窗口进行某些特定操作引起窗口重绘时,会发送WM_PAINT消息
---系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时等等
---大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和InvalidateRgn函数来完成的。
---ON_WM_PAINT可以捕获此消息,并自己调用OnPaint()函数来实现对某些要素图形的重新绘制

---当然,视频里面省略了一个

#在消息响应函数的基础上,区分Win32Api和MFC
---如果是传统的Win32Api的调用,分为设备对象(窗口),设备上下文(内存),图形对象
---通过设备对象获取窗口的设备上下文,然后自定义图形对象
---最后,将图形对象和设备上下文关联,调用WinApi进行绘图
---绘制图形如下(这个只能显示一次,而窗口是不停的绘制、渲染)
---这也是为什么上面MFC要利用dc对象来进行画图

#MFC的窗口句柄
---哪如何获得窗口类的自己的句柄呢?有如下方法:
---1、this->m_hWnd; //成员变量
---2、GetSafeHwnd(); //成员方法
---3、AfxGetMainWnd()->m_hWnd;
#在MFC里面模拟Win32Api的调用
---Hello.h
---hello.cpp:为什么OnPaint()里面调用:BeginPaint(m_hWnd,&ps)和EndPaint(m_hWnd,&ps)?
---BeginPaint函数的作用是告诉Windows系统,要开始向显示卡输出内容了,把这次显示的操作请求放到系统显示队列里。
---由于系统上的显示卡往往只有一个,那么这种资源是独占的,所以操作系统会让显示操作线性化,保证每个窗口的显示是独立进行的,而不是A窗口显示一部份,或者B窗口显示一部份,而是A窗口显示完成后再让B窗口显示
---因此,BeginPaint函数就是跟操作系统说,我需要显示了,你安排好吧。当BeginPaint返回时,就获取到系统的显示资源句柄,这样就可以调GDI一大堆函数来操作了
---显示完成后,一定要记得调用函数EndPaint,因为使用BeginPaint函数请求了独占的显示资源后,如果不释放回去,就会让其它程序永远获取不到显示资源了,这样系统就死锁了
---应用程序除了响应WM_PAINT消息外,不应该调用BeginPaint
---效果如下

---点击鼠标左键

---上面是Win32Api进行的操作,如果替换为MFC封装的DC类
---效果如下

#设备描述表的属性(重要)

---例如,修改字体的颜色
---效果如下

#鼠标左键点击,画一个黄色的矩形
---pen(1,2,3)相当于CreatePen(1,2,3)
---代码如下
---效果如下

---总结

第十一:WindowsGDI

#GDI的映射模式
---映射模式是设备描述表的属性,用于确定逻辑坐标值(内存)到设备坐标值(显示屏)的转换(设备坐标值:窗口中相对应的像素位置)
---传递给CDC(CDC封装了HDC和DC有关的函数)输出函数的逻辑坐标值,然后被转换为设备坐标值
---通过CDC::SetMapMode来进行设置逻辑设备到设备坐标的映射方式

#映射模式的nMapMode取值与含义
符号常量 数字常量 x方向 y方向 逻辑单位的大小
MM_TEXT 1 向右(默认)向下(默认) 像素
MM_LOMETRIC 2 向右 向上 0.1 mm
MM_HIMETRIC 3 向右 向上 0.01 mm
MM_LOENGLISH 4 向右 向上 0.01 in
MM_HIENGLISH 5 向右 向上 0.001 in
MM_TWIPS 6 向右 向上 1/1440 in
MM_ISOTROPIC 7 自定义 自定义 自定义
MM_ANISOTROPIC 8 自定义 自定义 自定义

#设备空间下的坐标
---1.客户区坐标 2.屏幕坐标 3.全窗口坐标

#GDI坐标空间
---Windows程序利用坐标空间和转换来对图形输出进行缩放、旋转、平移、斜切、反射等
---坐标空间是一个平面的空间,通过互相垂直的XY轴来定位二维对象
#Win32Api使用4种坐标空间

---在窗口的ON_WM_PAINT()消息的响应函数OnPaint()中
---绘制圆形
---这里的映射模式是默认的以像素为映射:MM_TEXT

---如果将映射模式设置为:MM_LOMETRIC(修改的是逻辑坐标的单位)
---一个逻辑单位:0.1毫米,x和y轴方向:x+y-
---效果如下
---映射模式的修改优点:与物理设备无关如显示器,不同的屏幕具有不同的分辨率

---获取客户区的逻辑坐标,使得圆形铺满整个窗口
---圆形可以铺满整个窗口,但是一旦放大窗口,就会变成椭圆

---可以通过修改映射模式进行自适应,发现放大了之后,圆也不会变成椭圆
---将映射模式改为:MM_ANISOTROPIC,发现逻辑单位还是1个像素点,但是放大之后,就会变成椭圆
---通常情况下SetWindowExt()函数和SetViewportExt()函数成对调用(我这里在网上找了一个例子)
---在X轴方向,每个逻辑单位有 1024 / 10240 个像素,
---而在Y轴方向,每个逻辑单位有 768 / 7680 个像素
#总结

#对应鼠标左键点击消息ON_WM_LBUTTONDOWN()对应的响应函数:OnLButtonDown(UINT nFlags,CPoint point)
---这里就是在以鼠标点击的点为源点(设备坐标),然后画矩形
---效果如下

---我们设置映射模式,将原本的默认的映射,改为:MM_LOMETRIC
---:一个逻辑单位=0.1毫米,x轴y轴方向:X+Y-
---效果如下:

#先设置CMianWindow主窗口的范围(0,0,515,540)
---发现画一个(0,0,500,500)的圆形正好在中间

---现在更改窗口的原点,改为逻辑坐标的(100,100)

#窗口和视口的绘图
---窗口中的坐标都是逻辑坐标,视口中的坐标都是设备坐标。我们的绘图语句(dc的成员函数)中用的坐标都是逻辑坐标
---这里窗口的原点,变成了逻辑坐标的(100,100),截取了一个小正方形,并且会补充一部分的空白
--而窗口到视口的映射方式没有变化,所以显示是部分的圆

---如果改为
---效果如下圆形直接显示完全

---背后的原理如下:先创建窗口,然后在窗口中绘制(100,100,500,500)的圆形
---在逻辑坐标画好之后,截取(100,100)为原点的部分

---更改视口
---效果如下:

---原理分析:将窗口的映射到视口上,由于在逻辑坐标上,窗口是完整的,所以圆形不会缺失(大小:500,500)
---但是视口上,只有(400,400)来接受映射会舍弃一部分,所以视口原点在原来的视口基础上,变成了原来视口的坐标位置的(100,100)开始
---总结:
---要更改 窗口/视口 原点,就在原来 窗口/视口 坐标系的基础上,进行 窗口/视口 的原点定位
---然后进行投影,没有投影到的部分,就是空白区域

#页面控件到设备空间的转换
---根据映射方式来确定绘图操作单位大小的一种度量转换

第十二:GDI绘图

#常用的绘图函数
---:MoveTo:在画线前设定当前的位置(指定起始)
---:LineTo:从当前位置画1条线到指定位置(指定指定终止)
---:Polyline:将一系列的点用线段连接起来(无需指定起始位置)
---:PolylineTo:从当前位置开始,将一系列点用线段连接起来(需要指定起始位置)
---:Elipse:画圆或者画椭圆
---:Rectangle:画一个带直角的矩形
---:FillRect:用指定画刷填充矩形
---:Draw3dRect:实现3D立体感
---效果如下

---也可以通过Polyline将一系列的点进行连接
---当然也可以PolylineTo函数,需要设定起始位置,但是和Polyline没有本质的区别
---效果如下

---系统中的画刷、画笔、字体等,可以自己创建并设计,也可以使用系统内置的
---CreateStockObject表示使用系统内置,LTGRAY_BRUSH是一个内置宏
---Windows的系统预定义的画刷如下
---CreateStockObject的优点:无需用dc.SelectObject()去更换画刷对象
---效果如下:

#如果鼠标点击在矩形内,就修改窗口名称
---效果如下,点击矩形内,窗口名改为:yes,点击其它区域,窗口名:no

---如果想改变矩形边框的颜色,风格,可以使用pen
---对于画笔、画刷等图形对象,在MFC中GDI的函数中可以使用:SelectObject()函数加载,并且返回了原来的图形对象,可以在后面加载原来的图形对象
---为什么要保存原来的图形对象:因为GDI没有异常机制,载入自定义的pen之后,在退出的时候,先调用的默认pen的析构函数,再调用dc的析构函数
---但是dc里面存在的是自定义的pen,而默认的pen已经优先释放了,所以会产生异常
---设置字体的大小,风格
---效果如下

---更大范围的更改字体:通过LOGFONT结构体来进行更大范围的字体的传参
---效果如下:

---带阴影的字体:
---效果如下

#作业
---用GDI绘制一个excel: Draw3dRect; FillRect; 填充之后画像
---注意我的主窗口大小
---思路:先两点连线,画出表格
---然后自定义画笔,画刷,填充横轴、纵轴的区域
---效果如下:

第十三:鼠标消息
#Windows鼠标消息
---Windows有20多种不同的消息,用来报告与鼠标有关的输入事件
---这些消息分为:客户消息和非客户消息,我们只需要关注客户消息(知识点:理解客户消息和非客户消息)
#客户区域的鼠标消息
#按下鼠标左键输出鼠标点击的坐标(注意:point是物理的设备坐标)
---效果如下:

#鼠标移动并且按下鼠标左键才能显示坐标
---定义的鼠标消息
---定义消息映射
---定义移动鼠标的消息响应函数
---效果如下:需要同时按3个键盘

#窗口的非客户区消息
---定义非客户区域的消息映射
---重写映射函数
---效果如下:只有在非客户区域才能接受消息

---自定义部分非客户区的消息处理
---只有点击系统菜单,才改变窗口的名字
#窗口在接收到客户、非客户区消息之前,先接受到:光标的屏幕坐标(很重要)
---通过 ON_WM_NCHITTEST() 确定光标在客户区 or 不在客户区
---在BEGIN_MESSAGE_MAP中添加ON_WM_HITTEST(),
---然后添加头文件,重写相应的响应函数
---发现可以像非客户区域一样,拖动客户区区域
#鼠标位置画直线(注意不能和上面的将客户区改为非客户区的一起,不然只能拖到窗口)
---注意,在两个消息处理函数之间,需要通过全局的CPoint来传递鼠标的位置
---然后通过OnLButtonDown来进行初始坐标的传输
---通过SetCapture/GetCapture来确保鼠标的位置被当前窗口捕获(即使在窗口之外)
---利用OnLButtonUp来进行绘图操作
---效果如下

---作业1:鼠标画一条红色的直线(思路:自定义画笔)
---效果如下

---作业2:Ctrl+鼠标左键画一个矩形
---效果如下:特点是鼠标在窗口外面,任然可以画

---作业3:鼠标右键画一条黄色的线条(非直线)
---思路:捕获鼠标光标滑动的地址,然后将这些点通过直线连接起来,从宏观上来看就是曲线
---思路是这样,但是好像原点都是按下的初始点
---但是我记得LineTo之后,原点是会改变的,不知道为啥不行

第十四:键盘消息
---通过给拥有输入焦点的窗口发送:WM_KEYDOWN 和 WM_KEYUP 消息
---来报告按钮是按下还是松开的事件,这些被称为按击键消息
---除了 ALT 和 F10 以外的所有按键都产生按下/抬起的消息
---而 Alt 和 F10 是系统键,对 Window 具有特殊的意义
#键盘消息
---在BEGIN_MESSAGE_MAP中,添加: ON_WM_KEYDOWN()
---部分的虚拟键代码(VK_CANCEL代码是一个虚拟键码,它包括同时按下两个键(Ctrl-Break))

---Backspace、Tab、Enter、Esc和空格——通常用于Windows程序。不过,Windows一般用字元讯息(而不是键盘讯息)来处理这些键
---Windows程序通常不需要监视Shift、Ctrl或Alt键的状态

---重写消息响应函数
---通过调试模式运行,发现Ctrl对应的十进制代码,以及之前的状态都是抬起
---但是一直按却没有1的出现
---在DeBugView中一直按下Ctrl也没有出现1,奇怪

#获取区分大小写的键盘消息,在消息映射中添加:ON_WM_CHAR()
---重写映射函数
---效果如下:
# ON_WM_CHAR 和 ON_WM_KEYDOWN 的区别
---ON_WM_CHAR是通过TranslateMessage翻译之后,转换为ASCII码
---不经过翻译是无法识别按键的大小写的
---当然,也可以判断Shift键的状态来判断大小写
---视频里面'VK_A'不加''的话编译不通过,但是加了''在调试的时候看不到输出。不知道问题出在哪里?
#设置键盘消息的钩子函数:SetWindowsHookEx
#钩子函数的定义
---钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。
---当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
----钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,
---这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递
#钩子函数的原理
---每一个Hook都有一个关联的指针列表,称之为钩子链表
---这个列表的指针指向钩子的各个处理子程序
----当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程
---最近安装的钩子放在链的开始,而最早安装的钩子放在最后,后加入的先获得控制权
---SetWindowsHookEx()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子
----线程钩子用于监视指定线程的事件消息,一般在当前线程或者当前线程派生线程内---
---系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中
---系统自动将包含“钩子回调函数”的DLL映射到受钩子函数影响的所有进程的地址空间中,即将这个DLL注入了那些进程
---几点说明:
(1)如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。
(2)对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。
(3)钩子特别是系统钩子会消耗消息处理时间,只有在必要的时候才安装钩子,在使用完毕后要及时卸载
#挂一个全局的键盘钩子(系统钩子)

---选择静态链接库(VC6的版本太老了,只能选择静态链接库)

---生产的静态链接库的HOOK函数如下

#思路:1.做一个导出函数StartHook(),由HelloMFC调用2.安装一个鼠标Hook,将鼠标消息再传输给主程序
---在HelloMFC的hello.cpp的OnKeyDown消息响应函数中,调用SetWindowsHookEx()函数,截获发送给键盘消息响应函数的键盘按下消息
---在HOOKDLL.cpp中设置具体的钩子的子程序
---设置钩子的类型为低水平的键盘钩子:WH_KEYBOAD_LL,可以看到右边是对应的钩子的处理函数地址LowLevelKeyboardProc

---WH_KEYBOAD_LL的处理函数如下:
---如果 nCode 小于零,则挂钩过程必须返回 CallNextHookEx 返回的值
---如果 nCode 大于或等于零,建议调用 CallNextHookEx 并返回返回的值
---在CallNextHookEx的功能:可以将钩子信息传递到当前钩子链中的下一个子程,一个钩子程序可以调用这个函数之前或之后处理钩子信息。
---在HOOKDLL.cpp文件中,设定导出函数StartHook()
---1.先获取窗口句柄 2.创建键盘HOOK,定义HOOK处理函数 3.在HOOK处理函数中,将hook后的信息,传递给钩子链的下一个子钩子
---在HOOKDLL.def将定义的StartHook函数进行导出
---将HOOKDLL.dll拷贝到HelloMFC的根目录(这里是动态链接库)

---在HelloMFC中,对按下F2的键盘消息,设置键盘钩子
---在hello.h中定义函数StartHook()
---自定义Hook函数,本质是调用DLL中的StartHook函数
---传入当前窗口的句柄(MFC封装了,但是源代码封装了m_hWnd)
---在键盘按下消息响应函数,按下F2键,就调用HOOK键盘的消息
---HOOK成功就修改窗口名称
---效果如下

----但是我在消息响应函数里面弹窗,发现没有报错,但是F2没有进行弹窗
---而且视频里面也是在HOOKDLL.dll的hook处理函数进行判断的(不知道为什么不能再消息响应函数里面进行MessageBox)
---视频里面是之间在Hook的处理函数里面LowLevelKeyboardProc函数,存在3个参数
---不管HOOK成功与否,都将调用CallNextHookEx将消息传递给钩子链的下一个HOOK
---KBDLLHOOKSTRUCT的内容如下

---修改HOOK处理函数,对拦截的消息进行预先处理
---将更新后的HOOKDLL.dll重新复制到HelloMFC,并且运行
---emmm,我这里还是没有消息弹窗,难受
#通过自定义消息,如果HOOK成功,向主窗口发送自定义消息,然后主窗口处理
---在HelloMFC中使用:ON_MESSAGE自定义消息,传参为自定义的消息类型,消息的响应函数
---然后窗口接到了消息,根据第一个wParam参数,判断是否为键盘按下消息,如果是的话就弹窗
---我这里存在弹窗不能出现的问题,猜测是W11是不支持吧,建议开个虚拟机在Xp上运行VC6
---效果如下

第十五:MFC对话框
---MFC的对话框就是一个窗口,不仅可以接受消息,还可以被移动和关闭,还可以在它的客户区域进行绘图
---我们可以把它看成是一个大容器,在上面能够放置各种各样的控件,使得程序的支持用户输入的手段更加的丰富。

---创建一个MFC的exe文件

---选择Dialog框(基本对话框)

---去掉所有的添加,只创建一个基本的Dialog框(基本对话框)
---不生成源文件备注,使用静态的DLL

---默认生成以下文件

---在#include "stdafx.h"之前的默认都不编译,所以111不会报错
---也就是说:#include "stdafx.h"是MFC的编译的第一行
---我们可以看到:theApp就是之前全局变量CMyApp
---InitInstance就是之前的WinMain主函数
---在里面也可以看到消息映射
---点击DialogTest.rc是一个资源脚本
---可以在rc里面添加一些版本信息等

---可以在项目的目录下面查看DiaLogTest.rc的部分具体代码
---可以看到IDD_DIALOGTEST_DIALOG 的风格、标题、字体、消息等等
---有两个按钮,确定、取消 和 “在这里设置对话控制”
---点击IDD_DIALOGTEST_DIALOG右边的窗口图,然后查看属性
---发现对应的DiaLogTest.rc的内容在这里凸显

---向Dialog框,添加一个控件

---发现在DiaLogTest.rc里面也添加了一行按钮的代码
---在DiaLogTestDlg.cpp文件中,存在着DoDataExchange()的函数
---这个是添加相应按钮的响应函数,这个函数是一种动态绑定技术,
---什么是动态绑定技术?
---添加一个名为:IDC_EDIT1的编辑框

---添加按钮的消息响应函数,使得按下按钮,改变编辑框里面的值

---代码如下
---发现编辑框的内容发生了改变

---也可以在:类向导 > 成员变量 > IDC_EDIT1 (控件ID) >添加成员变量
---相当于原来是通过GetDlgItem(IDC_EDIT1)来获取IDC_EDIT1的函数地址(指针)
---现在通过给Dialog框的控件创建成员变量,进而更好的调用方法

---通过成员变量,调用方法来改变编辑框的值
---效果如下

---可以看到,这里的动态绑定,添加了控件的绑定:IDC_EDIT1和m_edit1进行绑定
---我们操作m_edit1就会改变IDC_EDIT1的控件
---在类向导里面的成员变量,删除IDC_EDIT1的成员变量
---添加成员变量和m_edit1绑定,添加Value(之前是Control),Value的类似是CString(字符串数组)

---定义m_edit的长度为255

---发现动态绑定的地方发生了改变
---在OnButton1控件的映射函数修改m_edit1的值,赋值为一个字符串
---发现编辑框控件的值同样发生了改变,之前相当于获取了IDC_EDIT1函数地址(指针),然后调用方法修改编辑框的值
---这里是将medit1数组和IDC_EDIT1关联,然后更新编辑框控件的值

---UpdateData(FALSE)和UpdateData(TRUE)的区别
---例如,在初始化的时候将空间的内容传递给edit1
---在显示的时候,不点击Button1,IDC_EDIT1编辑框也会显示test
---在DoModal()里面:就是一个模态对话框
---在DoModal()里面实现了Dialog框的绘制,输出、消息循环
---并且默认了两个按钮:确认和取消,分别对应下面的IDOK和IDCANCEL
---在int nResponse = dlg.DoModal();处下断点,然后点击确定,发现nResponse的值为1
---同样,点击取消,nResponse的值为2
---可以看到不同的按钮对应不同的值
---为确定按钮添加消息响应函数

---发现确定按钮调用的是CDialog::OnOK();,在这里下断点进去查看
---注意,这里是先进入BOOL CDiaLogTestApp::InitInstance()
---然后在 int nResponse = dlg.DoModal();创建、显示Dialog框,并设置消息循环
---然后再按下确定按钮,根据nResponse的值,来调用CDiaLogTestDlg::OnOK()
---发现CDiaLogTestDlg::OnOK()的本质是调用EndDialog(IDOK);方法
---如果是CDiaLogTestDlg::IDCANCEL()就调用EndDialog(IDCANCEL);
---模态对话框(就是Dialog框)会造成一个结果:对话框卡在屏幕,双击rc

---插入一个新的Dialog框

---新建的Dialog框创建一个名为CDialog1的新类

---然后发现CDialog1类里面存在2各确定和取消的按钮
---而且在FileView路径下

---在DiaLogTest.cpp中,#include "Dialog1.h"
---然后在OnButton1()的响应函数里面
---发现带点击OnButton1,就会弹出第二个Dialg对话框
---而且只能将模态对话框关闭之后,才能进行主窗口的操作(可以当作验证,如果不能通过密码验证,就不能使用主窗口)

---如果是非模态对话框,就不能通过DoModal函数
---但是这样创建的窗口,只会一闪而过(原因是在void CDiaLogTest2Dlg::OnButton1()
函数结束之后,dlg对象就会被释放掉)
---解决方法:采用在堆中创建对象(new一个对象)
---但是存在问题:new了对象,但是没有释放对象
#解决方法1
---在Dialog的取消控件,添加响应函数

---将原来的CDialog::OnCancel();删除,替换为销毁窗口
---为什么要改写呢?是因为:这里原本的方法是对应的DoModal的模态对话框
---这里是非模态对话框,所以需要重写取消的函数,删除对话框
---为Dialog1的PostNCDestroy(在视图窗口关闭时最后调用的成员函数,即删除视图对象)消息添加消息响应函数

---由于DestroyWindow();最后会产生PostNcDestroy()消息
---重写PostNcDestroy()消息,在这里添加销毁堆内存中new的对象
#解决方法2(更简洁):
---在CDiaLogTest2Dlg.h中,首先#include "Dialog1.h",其次CDialog1* dlg;
---OnButton1() 的消息响应函数不需要声明CDialog1的指针
---在CDiaLogTest2Dlg的DestroyWindow消息中,建立消息响应函数

---销毁窗口
---DestroyWindow和PostNcDestroy的区别
---综合以上:先调用DestroyWindow,在此间会有OnDestroy消息,接着窗口被销毁
---于是DestroyWindow返回TRUE,
---然后是OnNcDestroy消息,之后再调用PostNcDestroy。
#模态对话框:
---产生一个窗口卡在前一个窗口,用dlg.DoModual返回参数
---根据参数的返回值来判断是按下确定还是取消
#非模态对话框
---不能直接调用局部变量调用,需要new一个对象
---然后去创建、显示,以及手动的释放对象

