MFC常识性知识汇总

目录

1.BitMap与Dc间的关系.

2.由位图bitmap对象到位图文件保存.

3. OnOK()、OnCancel()、OnClose()、OnDestroy() 对话框概念.

4.OnDrow和OnPaint的区别

5.MFC文档视图

6.MFC框架间联立的方法

7.Document(文档)、View(视图)、Frame(框架)、App(应用)之间相互访问

8.MFC类视图

9.MFC消息映射宏.

10.模态对话框的创建与销毁.

11.OLE接口详解.

12.MFC控件关联变量

13.注册系统热键<不能Ctrl + p>

14.多文档应用

15.MFC隐藏模态对话框、

16.Windows下实现程序托盘效果.


1.BitMap与Dc间的关系.

[cpp]  view plain  copy
  1. //获取窗口DC  
  2. HDC hdc = GetDC(hWnd);  
  3. //获取窗口的客户区区域  
  4. RECT rect;  
  5. GetClientRect(hWnd, &rect);  
  6. //获取当前窗口的位图  
  7. HDC hMemDC = CreateCompatibleDC(hdc);  
  8. HBITMAP hBitmapSrc;  
  9. hBitmapSrc = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  
  10. SelectObject(hMemDC, hBitmapSrc);  
  11. BitBlt(hMemDC, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);  
  12. SaveBitmap(hBitmapSrc , "C:\\123.bmp");     // SaveBitmap()是自定义的一个函数,用来把传递进来的位图句柄保存成图片文件  
  13. // 结果是C:\\123.bmp内容是hWnd的窗口内容  



原来一直觉得,HBITMAP选进设备DC以后,是将图片数据拷贝到DC上,从这段代码当然这里自然而然猜想,HBITMAP选进DC后,对DC的操作会影响到HBIMAP。

于是添加了如下测试代码:


[cpp]  view plain  copy
  1. //把窗口填充成白色  
  2.     SelectObject(hdc, GetStockObject(WHITE_PEN));  
  3.     SelectObject(hdc, GetStockObject(WHITE_BRUSH));  
  4.     Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);  
  5.   
  6.     HDC hMemDC2 = CreateCompatibleDC(hdc);  
  7.     SelectObject(hMemDC2, hBitmapSrc);  
  8.     BitBlt(hdc, 0, 0, rect.right, rect.bottom, hMemDC2, 0, 0, SRCCOPY);  
先把原窗口拷贝成白色,然后再把选入了hBitmapSrc的内存DC拷贝到原窗口上,测试发现,窗口还是白色,无效。这是为什么呢。

百度下CreateCompatibleBitmap,发现百度百科里面介绍:


HDC hdc=GetDC(hwnd);
HDC memdc=CreateCompatibleDC(hdc);
RECT rc;
BITMAP bmp;
HBITMAP holdbmp,hbmp=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_CLOCK));//从资源加载位图
holdbmp=(HBITMAP)SelectObject(memdc,hbmp);//这里把hbmp的位图选择到兼容DC memdc,之后这个兼容DC就拥有和
//hbmp同样大小的绘图区域,注意超出位图返回的GDI输出都是无效的.
GetObject(hbmp,sizeof(BITMAP),&bmp);//这里获取 位图的大小信息,事实上也是兼容DC绘图输出的范围
SetRect(&rc,0,0,bmp.bmWidth,bmp.bmHeight);
DrawText(memdc,"Center Line Text" -1,&rc,DT_VCENTER|DT_SINGLELINE|DT_CENTER);//在兼容DC中间位置输出字符串
//这样以来我们就相当于把hbmp这个位图加上了文字标注,我们可以把这个增加了文字标注的位图保存起来.一个简单的图像处理基本就OK了.
SelectObject(memdc,holdbmp);//复原兼容DC数据.
DeleteDC(memdc);
ReleaseDC(hwnd, hdc);

这说明我的猜想是对的,如果HBITMAP选进了DC,对DC的操作的确会影响到HBITMAP。但代码测试不无效时为什么呢。
突然想到,可能使一个HBITMAP不能同时选进两个DC。做了如下测试
[cpp]  view plain  copy
  1. //获取窗口DC  
  2. HDC hdc = GetDC(hWnd);  
  3.   
  4. //获取窗口的客户区区域  
  5. RECT rect;  
  6. GetClientRect(hWnd, &rect);  
  7.   
  8. //获取当前窗口的位图  
  9. HDC hMemDC = CreateCompatibleDC(hdc);  
  10. HBITMAP hBitmapSrc;  
  11. hBitmapSrc = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  
  12. HGDIOBJ hOldBt = SelectObject(hMemDC, hBitmapSrc);  // 修改,保存老位图句柄  
  13. BitBlt(hMemDC, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);  
  14.   
  15. //获取当前窗口位图的像素颜色数据  
  16. BYTE *pBitmapDataSrc = new BYTE[(rect.right-rect.left)*(rect.bottom-rect.top)*4];  
  17. GetBitmapBits(hBitmapSrc, (rect.right-rect.left)*(rect.bottom-rect.top)*4, pBitmapDataSrc);  
  18.   
  19. //把窗口填充成白色  
  20. SelectObject(hdc, GetStockObject(WHITE_PEN));  
  21. SelectObject(hdc, GetStockObject(WHITE_BRUSH));  
  22. Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);  
  23.   
  24. TextOut(hMemDC, 100, 100, _T("123456abcd"), 10);        // 新加内容,为了验证是否是之后拷贝上去的,多画了点东西    
  25. SelectObject(hMemDC, hOldBt);                           // 新加内容  
  26. HDC hMemDC2 = CreateCompatibleDC(hdc);  
  27. SelectObject(hMemDC2, hBitmapSrc);  
  28. BitBlt(hdc, 0, 0, rect.right, rect.bottom, hMemDC2, 0, 0, SRCCOPY);  
  29. return;  


验证无误。

原文转载自:http://blog.csdn.NET/qscjob/article/details/18995725


[cpp]  view plain  copy
  1. //获取窗口DC  
  2. HDC hdc = GetDC(hWnd);  
  3. //获取窗口的客户区区域  
  4. RECT rect;  
  5. GetClientRect(hWnd, &rect);  
  6. //获取当前窗口的位图  
  7. HDC hMemDC = CreateCompatibleDC(hdc);  
  8. HBITMAP hBitmapSrc;  
  9. hBitmapSrc = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  
  10. SelectObject(hMemDC, hBitmapSrc);  
  11. BitBlt(hMemDC, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);  
  12. SaveBitmap(hBitmapSrc , "C:\\123.bmp");     // SaveBitmap()是自定义的一个函数,用来把传递进来的位图句柄保存成图片文件  
  13. // 结果是C:\\123.bmp内容是hWnd的窗口内容  



原来一直觉得,HBITMAP选进设备DC以后,是将图片数据拷贝到DC上,从这段代码当然这里自然而然猜想,HBITMAP选进DC后,对DC的操作会影响到HBIMAP。

于是添加了如下测试代码:


[cpp]  view plain  copy
  1. //把窗口填充成白色  
  2.     SelectObject(hdc, GetStockObject(WHITE_PEN));  
  3.     SelectObject(hdc, GetStockObject(WHITE_BRUSH));  
  4.     Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);  
  5.   
  6.     HDC hMemDC2 = CreateCompatibleDC(hdc);  
  7.     SelectObject(hMemDC2, hBitmapSrc);  
  8.     BitBlt(hdc, 0, 0, rect.right, rect.bottom, hMemDC2, 0, 0, SRCCOPY);  
先把原窗口拷贝成白色,然后再把选入了hBitmapSrc的内存DC拷贝到原窗口上,测试发现,窗口还是白色,无效。这是为什么呢。

百度下CreateCompatibleBitmap,发现百度百科里面介绍:


HDC hdc=GetDC(hwnd);
HDC memdc=CreateCompatibleDC(hdc);
RECT rc;
BITMAP bmp;
HBITMAP holdbmp,hbmp=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_CLOCK));//从资源加载位图
holdbmp=(HBITMAP)SelectObject(memdc,hbmp);//这里把hbmp的位图选择到兼容DC memdc,之后这个兼容DC就拥有和
//hbmp同样大小的绘图区域,注意超出位图返回的GDI输出都是无效的.
GetObject(hbmp,sizeof(BITMAP),&bmp);//这里获取 位图的大小信息,事实上也是兼容DC绘图输出的范围
SetRect(&rc,0,0,bmp.bmWidth,bmp.bmHeight);
DrawText(memdc,"Center Line Text" -1,&rc,DT_VCENTER|DT_SINGLELINE|DT_CENTER);//在兼容DC中间位置输出字符串
//这样以来我们就相当于把hbmp这个位图加上了文字标注,我们可以把这个增加了文字标注的位图保存起来.一个简单的图像处理基本就OK了.
SelectObject(memdc,holdbmp);//复原兼容DC数据.
DeleteDC(memdc);
ReleaseDC(hwnd, hdc);

这说明我的猜想是对的,如果HBITMAP选进了DC,对DC的操作的确会影响到HBITMAP。但代码测试不无效时为什么呢。
突然想到,可能使一个HBITMAP不能同时选进两个DC。做了如下测试
[cpp]  view plain  copy
  1. //获取窗口DC  
  2. HDC hdc = GetDC(hWnd);  
  3.   
  4. //获取窗口的客户区区域  
  5. RECT rect;  
  6. GetClientRect(hWnd, &rect);  
  7.   
  8. //获取当前窗口的位图  
  9. HDC hMemDC = CreateCompatibleDC(hdc);  
  10. HBITMAP hBitmapSrc;  
  11. hBitmapSrc = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  
  12. HGDIOBJ hOldBt = SelectObject(hMemDC, hBitmapSrc);  // 修改,保存老位图句柄  
  13. BitBlt(hMemDC, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);  
  14.   
  15. //获取当前窗口位图的像素颜色数据  
  16. BYTE *pBitmapDataSrc = new BYTE[(rect.right-rect.left)*(rect.bottom-rect.top)*4];  
  17. GetBitmapBits(hBitmapSrc, (rect.right-rect.left)*(rect.bottom-rect.top)*4, pBitmapDataSrc);  
  18.   
  19. //把窗口填充成白色  
  20. SelectObject(hdc, GetStockObject(WHITE_PEN));  
  21. SelectObject(hdc, GetStockObject(WHITE_BRUSH));  
  22. Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);  
  23.   
  24. TextOut(hMemDC, 100, 100, _T("123456abcd"), 10);        // 新加内容,为了验证是否是之后拷贝上去的,多画了点东西    
  25. SelectObject(hMemDC, hOldBt);                           // 新加内容  
  26. HDC hMemDC2 = CreateCompatibleDC(hdc);  
  27. SelectObject(hMemDC2, hBitmapSrc);  
  28. BitBlt(hdc, 0, 0, rect.right, rect.bottom, hMemDC2, 0, 0, SRCCOPY);  
  29. return;  


验证无误。

原文转载自:http://blog.csdn.NET/qscjob/article/details/18995725


2.由位图bitmap对象到位图文件保存.

最近正在着手开发一个图片库,也就是实现对常见图片格式的度写操作。作为总结与积累,我会把这些图片格式以及加载的实现写在我的Blog上。

说到图片,位图( Bitmap)当然是最简单的,它 Windows显示图片的基本格式,其文件扩展名为 *.BMP。在 Windows下,任何各式的图片文件(包括视频播放)都要转化为位图个时候才能显示出来,各种格式的图片文件也都是在位图格式的基础上采用不同的压缩算法生成的( Flash中使用了适量图,是按相同颜色区域存储的)。
一、下面我们来看看位图文件( *.BMP)的格式。
位图文件主要分为如下 3个部分:

块名称
对应Windows结构体定义
大小(Byte
文件信息头BITMAPFILEHEADER14
位图信息头BITMAPINFOHEADER40
RGB颜色阵列BYTE*由图像长宽尺寸决定


既然要保存为位图,那就应该正确按照位图未见格式向其写入数据.1.FILEHEADER,2.INFOHEADER,3.数据部分为BITMAP对象中的值,通过GetDIBits来获取.

说他多估计懵逼,文档末尾有我的demo.自己慢慢研究吧,涉及到其它项目的内容,自己查阅判断并合理利用.


1、 文件信息头 BITMAPFILEHEADER
结构体定义如下:
typedef struct tagBITMAPFILEHEADER {
UINT bfType; 
DWORD bfSize; 
UINT bfReserved1; 
UINT bfReserved2; 
DWORD bfOffBits;
} BITMAPFILEHEADER;
其中:
bfType说明文件的类型,该值必需是0x4D42,也就是字符'BM'。
bfSize说明该位图文件的大小,用字节为单位
bfReserved1保留,必须设置为0
bfReserved2保留,必须设置为0
bfOffBits说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
2、位图信息头 BITMAPINFOHEADER
结构体定义如下:
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; 
LONG biWidth; 
LONG biHeight; 
WORD biPlanes; 
WORD biBitCount; 
DWORD biCompression; 
DWORD biSizeImage; 
LONG biXPelsPerMeter; 
LONG biYPelsPerMeter; 
DWORD biClrUsed; 
DWORD biClrImportant;
} BITMAPINFOHEADER;
其中:
biSize说明BITMAPINFOHEADER结构所需要的字数。
biWidth说明图象的宽度,以象素为单位。
biHeight说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
biPlanes为目标设备说明位面数,其值将总是被设为1。
biBitCount说明比特数/象素,其值为1、4、8、16、24、或32。但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像。
biCompression说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:BI_RGB
biSizeImage说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
biXPelsPerMeter说明水平分辨率,用象素/米表示。
biYPelsPerMeter说明垂直分辨率,用象素/米表示。
biClrUsed说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
biClrImportant说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
3、RGB颜色阵列
有关 RGB三色空间我想大家都很熟悉,这里我想说的是在 Windows下, RGB颜色阵列存储的格式其实 BGR。也就是说,对于 24位的 RGB位图像素数据格式是:
蓝色B绿色G红色R
对于 32位的 RGB位图像素数据格式是:
蓝色B绿色G红色R透明通道A
透明通道也称 Alpha通道,该值是该像素点的透明属性,取值在 0(全透明)到 255(不透明)之间。对于 24位的图像来说,因为没有 Alpha通道,故整个图像都不透明。
二、搞清了文件格式,下一步我们要实现加载。
加载文件的目的是要得到图片属性,以及 RGB数据,然后可以将其绘制在 DC(GDI),或是生成纹理对象 (3D:OpenGL/Direct3D)。这两种用途在数据处理上有点区别,我们主要按前一种用法讲,在和 3D有不同的地方,我们再提出来。
1、加载文件头
//Load the file header
BITMAPFILEHEADER header;
memset(&header, 0, sizeof(header));
inf.read((char*)&header, sizeof(header));
if(header.bfType != 0x4D42)
return false;
这个很简单,没有什么好说的。
2、加载位图信息头
//Load the image information header
BITMAPINFOHEADER infoheader;
memset(&infoheader, 0, sizeof(infoheader));
inf.read((char*)&infoheader, sizeof(infoheader));
m_iImageWidth = infoheader.biWidth;
m_iImageHeight = infoheader.biHeight;
m_iBitsPerPixel = infoheader.biBitCount;
这里我们得到了 3各重要的图形属性:宽,高,以及每个像素颜色所占用的位数。
3、行对齐
由于 Windows在进行行扫描的时候最小的单位为 4个字节,所以当
图片宽  X 每个像素的字节数 ! = 4的整数倍
时要在每行的后面补上缺少的字节,以 0填充(一般来说当图像宽度为 2的幂时不需要对齐)。位图文件里的数据在写入的时候已经进行了行对齐,也就是说加载的时候不需要再做行对齐。但是这样一来图片数据的长度就不是:宽  X 高  X 每个像素的字节数 了,我们需要通过下面的方法计算正确的数据长度:
//Calculate the image data size
int iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel) + 31) >> 5) << 2;
m_iImageDataSize = iLineByteCnt * m_iImageHeight;
4、加载图片数据
对于 24位和 32位的位图文件,位图数据的偏移量为 sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是说现在我们可以直接读取图像数据了。
if(m_pImageData) delete []m_pImageData;
m_pImageData = new unsigned char[m_iImageDataSize];
inf.read((char*)m_pImageData, m_iImageDataSize);
如果你足够细心,就会发现内存 m_pImageData里的数据的确是 BGR格式,可以用个纯蓝色或者是纯红色的图片测试一下。
5、绘制
好了,数据和属性我们都有了,现在就可以拿来随便用了,就和吃馒头一样,爱粘白糖粘白糖,爱粘红糖粘红糖。下面是我的 GDI绘制代码,仅作参考。
void CImage::DrawImage(HDC hdc, int iLeft, int iTop, int iWidth, int iHeight)
{
if(!hdc || m_pImageData == NULL)
return;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth = m_iImageWidth;
bmi.bmiHeader.biHeight = m_iImageHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = m_iBitsPerPixel;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = m_iImageDataSize;
StretchDIBits(hdc, iLeft, iTop, iWidth, iHeight,
0, 0, m_iImageWidth, m_iImageHeight,
m_pImageData, &bmi, DIB_RGB_COLORS, SRCCOPY);
}
6、3D(OpenGL)的不同之处
如果你是想用刚才我们得到的数据生成纹理对象,那么你还要请出下面的问题。
首先,用来生成纹理的数据不需要对齐,也就是说不能在每行的后面加上对齐的字节。当然在 OpenGL里要求纹理图片的尺寸为 2的幂,所以这个问题实际上不存在;
其次,我们得到的图形数据格式是 BGR(BGRA),所以在生成纹理的时候,需指定格式为 GL_BGR_EXT(GL_BGRA_EXT);否则需要做 BGR->RGB(BGRA->RGBA)的转化。

自己的demo例子,待审阅查看.
/*
      
typedef struct tagBITMAP{
LONG bmType; //位图类型,必须为0
LONG bmWidth; //位图宽度
LONG bmHeight; //位图高度
LONG bmWidthBytes; //每一行像素所在的byte数
WORD bmPlanes; //颜色平面数
WORD bmBitsPixel; //像素的位数
LPVOID bmBits; //位图内存指针
}BITMAP;
以下,仅仅是创造了兼容性位图bmp,也就是说bmBits并不存在实质性数据,所以需要通过GetDIBits来获取位图数据.
*/

/*
延伸理解:BITMAP位图与DC间的关系:http://blog.csdn.net/qq_24571549/article/details/72821906

BITMAP对象是真正的图像数据,但就下面代码来说,
因为BITMAP是从无到有的构建,需要兼容dc和BITMAP<比如位图大小>等相关信息来填充BITMAPINFO 值,所以,你懂得.

总结:利用BITMAP和兼容dc来完善BITMAPINFO 和pdata<位图数据>信息.

*/

void CClientDlg::OnOK() 
{
CDC* pDeskDC =  GetDesktopWindow()->GetDC(); //获取桌面画布对象
CRect rc;
GetDesktopWindow()->GetClientRect(rc); //获取屏幕的客户区域


int width  = 300; //获取屏幕的宽度
int height = 300; //获取屏幕的高度


CDC  memDC;  //定义一个内存画布
memDC.CreateCompatibleDC(pDeskDC); //创建一个兼容的画布


CBitmap bmp; 
bmp.CreateCompatibleBitmap(pDeskDC,width,height); //创建兼容位图
memDC.SelectObject(&bmp); //选中位图对象

BITMAP bitmap;
bmp.GetBitmap(&bitmap);


float panelsize  = 0; //记录调色板大小
以下代码是获取调色板的长度,调色板现在的用处很少,因为256色的位图已经不多了。
if (bitmap.bmBitsPixel < 16) //判断是否为真彩色位图
{
int Data = bitmap.bmBitsPixel*sizeof(RGBQUAD);
panelsize = pow(2.0f, Data);
}


/*
typedef struct tagBITMAPINFO
{
   BITMAPINFOHEADER  bmiHeader;
   RGBQUAD           bmiColors[1];
}  BITMAPINFO;


*/
//这个实际上就是填充bmiHeader<BITMAPINFOHEADER>信息.
BITMAPINFO *pBInfo = (BITMAPINFO*)LocalAlloc(LPTR,sizeof(BITMAPINFO)+panelsize);
pBInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel;
pBInfo->bmiHeader.biClrImportant  = 0;
pBInfo->bmiHeader.biCompression   = 0;
pBInfo->bmiHeader.biHeight        = height;
pBInfo->bmiHeader.biPlanes        = bitmap.bmPlanes;
pBInfo->bmiHeader.biSize          = sizeof(BITMAPINFO);
pBInfo->bmiHeader.biSizeImage     = bitmap.bmWidthBytes*bitmap.bmHeight;
pBInfo->bmiHeader.biWidth         = width;
pBInfo->bmiHeader.biXPelsPerMeter = 0;
pBInfo->bmiHeader.biYPelsPerMeter = 0;
m_X = m_RecvX;
m_Y = m_RecvY;
memDC.BitBlt(0,0,width,height,pDeskDC,m_X,m_Y,SRCCOPY);
char* pData = new char[bitmap.bmWidthBytes* bitmap.bmHeight];


// 获取该调色板下新的像素值  


/*
GetDIBits是最重要的函数,真正获得位图数据的工作就由它完成,它第一个参数为HDC,第二个参数为位图句柄,第三个
参数为扫描行的开始行,一般为0,第四个为结束行,一般就是高度,第四个参数最重要,它表示接收数据的起始地址,这个
地址一般是在调色板之后。第五个参数指的是接收BITMAPINFO结构的地址,这个结构上面没有写,它其实就是BITMAPIN
FO结构加上调色板信息。最后一个参数是格式。一般是DIB_RGB_COLORS
*/
::GetDIBits(memDC.m_hDC,bmp,0,bitmap.bmHeight,pData,pBInfo,DIB_RGB_COLORS);


int BufSize = panelsize+ sizeof(BITMAPINFO)+bitmap.bmWidthBytes* bitmap.bmHeight;


memcpy(pSendBuf,pBInfo,sizeof(BITMAPINFO));
char* pHead = pSendBuf;
pSendBuf += sizeof(BITMAPINFO);
memcpy(pSendBuf,pData,bitmap.bmWidthBytes* bitmap.bmHeight);


///
BITMAPFILEHEADER bmheader;
memset(&bmheader, 0, sizeof(bmheader));
bmheader.bfType = 0x4d42;     //图像格式。必须为'BM'格式。  
bmheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + panelsize; //从文件开头到数据的偏移量  
bmheader.bfSize = ((width *bitmap.bmBitsPixel +31) /8) *height + bmheader.bfOffBits;//文件大小  这个结构包含图像大小信息和 bmheader.bfOffBits偏移量信息总和



static int  ncount = 0;
if (0 == ncount)
{
CFile MyBitMap("b.bmp", CFile::modeCreate | CFile::modeWrite);
MyBitMap.Write(&bmheader, sizeof(BITMAPFILEHEADER));
MyBitMap.Write(&(pBInfo->bmiHeader), sizeof(BITMAPINFOHEADER));
MyBitMap.Write(pData, bitmap.bmWidthBytes* bitmap.bmHeight);
MyBitMap.Close();


ncount++;
}



//


pSendBuf = pHead;
addr1.sin_family = AF_INET;
addr1.sin_port   = htons(5002);
addr1.sin_addr.S_un.S_addr = inet_addr(m_ServerIP);
//定义数据报的格式
/*序号2位||结束标记2位||位图数据||位图数据大小4位||屏幕X坐标2位||屏幕Y坐标2位||数据报大小4位*/


//定义每次发送位图数据的大小
bmpsize = GraphSize;
//计算每个位图发送的次数
count = BufSize / GraphSize;
mod   = BufSize % GraphSize;
if ( mod != 0)
count+=1;


m_FrameIndex = 0;
int ret = SendData(m_FrameIndex,mod,bmpsize,count,pSendBuf,addr1);


pSendBuf = pHead;
delete []pData;
LocalFree(pBInfo);


pDeskDC->DeleteDC();
bmp.DeleteObject();
memDC.DeleteDC();
}


3.OnOK()、OnCancel()、OnClose()、OnDestroy() 对话框概念.

重要的话写在前言:
    1.是否真正区分类函数重写概念.<比如点击对话框上"确定","取消",类函数重写导致ID事件绑定,自动调用你重写的函数>
    2.是否真正区分消息响应机制间关系.<WM_ClOSE消息绑定的是对话框右上角的"X",与OnCancel函数无关>
    3.理解消息路由间前后的关系.

对话框默认用的两个按钮的ID分别是IDOK和IDCANCEL,这两个都是在winuser.h 中预定义的系统标准控件ID。 
对于标准ID,你不重载时MFC会自动调用父类的相应处理函数。 
比如IDOK映射到CDialog::OnOK()函数,IDCANCEL映射到CDialog::OnCancel()。 
在这两个函数的源码如下: 
void CDialog::OnOK() 
{ 
if (!UpdateData(TRUE)) 
{ 
TRACE(traceAppMsg, 0, "UpdateData failed during dialog termination.\n"); 
// the UpdateData routine will set focus to correct item 
return; 
} 
EndDialog(IDOK); 
} 
void CDialog::OnCancel() 
{ 
EndDialog(IDCANCEL); 
} 
可以看出点击这两个按钮,都会调用EndDialog()来关闭对话框,只是返回值不同。 
EndDialog()函数调用了DestroyWindow()函数,DestroyWindow()函数又发送了WM_DESTROY消息,该消息的处理函数是OnDestroy(),对话框的生存期最后一个函数是PostNcDestroy()函数。 
点那个叉叉呢,首先向对话框发送WM_CLOSE消息,由OnClose()函数处理,它调用DestroyWindow(),其后是和上面一样的路由。 
可以看出点叉叉的时候绕过了OnOK()和OnCancel()。 
小结一下: 
1. 点“确定”、“取消”时的关闭路由为 
OnOK()或OnCancel() ---> EndDialog() ---> DestroyWindow() ---> OnDestroy() ---> PostNcDestroy() 
2. 点“关闭”标题栏按钮的关闭路由为 
OnClose()---> DestroyWindow() ---> OnDestroy() ---> PostNcDestroy() 
回答楼主的问题: 
请注意,上面提到的这些函数统统都是可以重载的,在重载时加入了你自己的代码后,应该调用父类CDialog同名的函数才能正确路由下去,否则就关不了对话框了。 
举个例子,重载了关闭的小叉叉 
void CAboutDlg::OnClose() 
{ 
// TODO: 在此添加消息处理程序代码和/或调用默认值 
DoSomthing(0; // 执行自己的判断等等 
// CDialog::OnClose(); // 把向导生成的父类调用给注释了,这时就关不了对话框了。 
}
补充回答,
点叉叉会发送WM_CLOSE消息,如果需要重载的话,应该在对话框的属性窗口中,选择WM_CLOSE消息来添加消息处理函数。
VS的IDE会自动添加如下三段:
1. xxx.h文件,类声明中加入OnClose()函数声明
 afx_msg void OnClose();
2. xxx.cpp文件,加入消息映射宏
 ON_WM_CLOSE() // 对于Windows标准消息,都是这种简短的格式。
3.  xxx.cpp文件,加入函数体
void CMyDlg::OnClose()
{
 CDialog::OnClose();
}
上述3处如果都正常的话,叉叉就映射到OnClose()了。
原文转载自:http://zhidao.baidu.com/question/62651044.html
4. nDrow和OnPaint的区别

OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。
OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。

The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.

在OnPaint中,将调用BeginPaint,用来获得客户区的显示设备环境,并以此调用GDI函数执行绘图操作。在绘图操作完成后,将调用EndPaint以释放显示设备环境。而OnDraw在BeginPaint与EndPaint间被调用。

1) 在mfc结构里OnPaint是CWnd的成员函数. OnDraw是CView的成员函数.
2) OnPaint()调用OnDraw(),OnPrint也会调用OnDraw(),所以OnDraw()是显示和打印的共同操作。

OnPaint是WM_PAINT消息引发的重绘消息处理函数,在OnPaint中会调用OnDraw来进行绘图。OnPaint中首先构造一个CPaintDC类得实例,然后一这个实例为参数来调用虚函数OnPrepareDC来进行一些绘制前的一些处理,比设置映射模式,最后调用OnDraw。而OnDraw和OnPrepareDC不是消息处理函数。所以在不是因为重绘消息所引发的OnPaint导致OnDraw被调用时,比如在OnLButtonDown等消息处理函数中绘图时,要先自己调用OnPrepareDC。 
至于CPaintDC和CClientDC根本是两回事情 CPaintDC是一个设备环境类,在OnPaint中作为参数传递给OnPrepareDC来作设备环境的设置。真正和CClientDC具有可比性的是CWindowDC,他们一个是描述客户区域,一个是描述整个屏幕。
如果是对CVIEW或从CVIEW类派生的窗口绘图时应该用OnDraw。
OnDraw()和OnPaint()有什么区别呢?
首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话框的程序中,只有OnPaint。
其次:我们在第《每天跟我学MFC》3的开始部分已经说到了。要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备(不单指你17寸的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响应,而CPaintDC支持重画。当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。
///CView默认的标准的重画函数
void CView::OnPaint() //见VIEWCORE.CPP
{

CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);    //调用了OnDraw
}
///CView默认的标准的OnPrint函数
void CView::OnPrint(CDC* pDC, CPrintInfo*)
{
ASSERT_VALID(pDC);
OnDraw(pDC);   // Call Draw
}

既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序。
///视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。
void CMyView::OnDraw( CDC* pDC )
{

CMyDoc* pDoc = GetDocument();
CString s = pDoc->GetData();
GetClientRect( &rect ); // Returns a CString CRect rect;
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}
最后:现在大家明白这哥俩之间的关系了吧。因此我们一般用OnPaint维护窗口的客户区(例如我们的窗口客户区加一个背景图片),用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口,具体的请参考MSDN吧。

OnDraw中可以绘制用户区域。OnPaint中只是当窗口无效时重绘不会保留CClientDC绘制的内容。

这两个函数有区别也有联系:

1、区别:OnDraw是一个纯虚函数,定义为virtual void OnDraw( CDC* pDC ) = 0; 而OnPaint是一个消息响应函数,它响应了WM_PANIT消息,也是是窗口重绘消息。

2、联系:我们一般在视类中作图的时候,往往不直接响应WM_PANIT消息,而是重载OnDraw纯虚函数,这是因为在CVIEW类中的WM_PANIT消息响应函数中调用了OnDraw函数,如果在CMYVIEW类中响应了WM_PAINT消息,不显式地调用OnDraw函数的话,是不会在窗口重绘的时候调用OnDraw函数的。
应用程序中几乎所有的绘图都在视图的 OnDraw 成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。)
OnDraw 重写:
通过调用您提供的文档成员函数获取数据。
通过调用框架传递给 OnDraw 的设备上下文对象的成员函数来显示数据。
当文档的数据以某种方式更改后,必须重绘视图以反映该更改。默认的 OnUpdate 实现使视图的整个工作区无效。当视图变得无效时,Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的设备上下文对象来响应该消息并调用视图的 OnDraw 成员函数。
当没有添加WM_PAINT消息处理时,窗口重绘时,由OnDraw来进行消息响应...当添加WM_PAINT消息处理时,窗口重绘时,WM_PAINT消息被投递,由OnPaint来进行消息响应.这时就不能隐式调用OnDraw了.必须显式调用(   CDC *pDC=GetDC(); OnDraw(pDC);   )..
隐式调用:当由OnPaint来进行消息响应时,系统自动调用CView::OnDraw(&pDC).

想象一下,窗口显示的内容和打印的内容是差不多的,所以,一般情况下,统一由OnDraw来画。窗口前景需要刷新时,系统会会调用到OnPaint,而OnPaint一般情况下是对DC作一些初始化操作后,调用OnDraw()。

OnEraseBkGnd(),是窗口背景需要刷新时由系统调用的。明显的一个例子是设置窗口的背景颜色(你可以把这放在OnPaint中去做,但是会使产生闪烁的现象)。  
至于怎么界定背景和前景,那要具体问题具体分析了,一般情况下,你还是很容易区别的吧。

的确,OnPaint()用来响应WM_PAINT消息,视类的OnPaint()内部根据是打印还是屏幕绘制分别以不同的参数调用OnDraw()虚函数。所以在OnDraw()里你可以区别对待打印和屏幕绘制。
其实,MFC在进行打印前后还做了很多工作,调用了很多虚函数,比如OnPreparePrint()等。

对于OnDraw() 
This method is called by the framework to render an image of the document. The framework calls this method to perform screen display, printing, and print preview, and it passes a different device context in each case. There is no default implementation


5.MFC文档视图

写在前言:怎么说呢,其实搞了好几天了,有点懵逼,似懂非懂.最终还是没有找到好的demo进行全面的分析.仅写,权当过程中总结.

总结:

CDocTemplate:给我的概念就是"类"概念.<这是个抽象类>

其派生类CSingleDocTemplate,CMultiDocTemplate.分别就是单文档和多文档类了.实际上应该关注的是他们的构造函数.所需皆为:nIDResource,pDocClass,pFrameClass,pViewClass.


想形成什么样的结果,就在构造函数中这块进行相应替换绑定.<但必须注意的是,要完善相关类和资源的绑定,比如类视图和类窗口资源>


/*可能存在多类进行联立设计实现,重点在于思想和设计*/

 

一:单文档的使用与理解

1直接在doc类中进行添加共有成员变量进行记录和控制.然后再view中就能直接通过getdocment返回指针进行访问doc中的数据了.

当窗口需要重绘时,view中的ondrow函数内部就会访问pdoc的指针,进行数据的获取了.看下创建工程源码即可.这样就实现了数据与现实分离开来了.

 

逻辑可行即可,比如示例:<以下文字逻辑阐述都是建立在利用vs创建的默认的单文档应用程序基础上>

         1.在doc类中添加共有成员变量.

         2.在程序开发设计中,处理鼠标按键消息,在其中进行通过getdocment获取文档指针,然后就能访问doc添加的共有成员变量进行信息存储了.

         3.在view中,就能直接通过getdocment进行指针获取,然后访问数据获得成员变量进行信息重现(或者重绘了)

<顺带插一句,还有可能进行封装设计,封装一个数据类,将对象封在doc类成员变量中,对外提供方法,这种设计也很巧妙>

 

进行文档插入解释:p184面的运行机制.有关多文档编程具备的基础知识.<STL的使用>p191

 

二:文档的读写

Getdocument函数负责文档和视图交互,但文档的数据要存盘或者读盘就要与磁盘进行数据传递,MFC提供一种读写文件简单的方法----“序列化”或者串行滑<serialize,类中有这个函数,所以提及>,实际上就是接口功能.

 

/*接下来就是介绍多文档的相关操作了.数据看到209面,进行实例化解说了*/

 

关于问题: http://blog.sina.com.cn/s/blog_63a881060102w8q2.html


<转载别人话,虽然能懂基本各个意思,但关联起来处理还不是很理解>:

程序初始化时保存窗口指针,或按层次关系直接获取。

 关于获得MFC窗口其它类指针的方法

关于获得MFC窗口其它类指针的方法(CSDN) 
访问应用程序的其它类 

获得CWinApp: 
-在CMainFrame,CChildFrame,CDocument,CView中直接调用AfxGetApp()或用theApp 
-在其它类中只能用AfxGetApp() 

获得CMainFrame: 
-在CMinApp中用AfxGetMainWnd()或者m_pMainWnd 
-在CChildFrame中可用GetParentFrame() 
-在其它类中用AfxGetMainWnd() 

获得CChildFrame: 
-在CView中用GetParentFrame() 
-在CMainFrame中用MDIGetActive()或GetActiveFrame() 
-在其它类中用AfxGetMainWnd()->MDIGetActive()或AfxGetMainWnd()->GetActiveFrame() 


获得CDocument: 
-在CView中用GetDocument() 
-在CChildFrame中用GetActiveView()->GetDocument() 
-在CMainFrame中用 
  -if SDI:GetActiveView()->GetDocument() 
  -if MDI:MDIGetActive()->GetActiveView()->GetDocument() 
-在其它类中 
  -if SDI:AfxGetMainWnd()->GetActiveView()->GetDocument() 
  -if 
MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument() 

获得CView: 
-在CDocument中 POSITION pos = GetFirstViewPosition();GetNextView(pos) 
-在CChildFrame中 GetActiveView() 
-在CMainFrame中 
  -if SDI:GetActiveView() 
  -if MDI:MDIGetActive()->GetActiveView() 
-在其它类中 
  -if SDI:AfxGetMainWnd()->GetActiveView() 
  -if MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView() 


不过要注意在doc中要取得view的指针C*View要注意类C*View声明的问题, 
因为默认情况下,mfc在*View.h中已经包含了*Doc.h,如果在*Doc.h中包含 
*View.h,就会引起嵌套包含问题,这样要在*Doc.h中加入 class C*View; 
而在*Doc.cpp中加入 #include "*View.h" 


转接相关图片联系:






实现这个工程的资源链接:http://download.csdn.NET/detail/qq_24571549/9778806


6.MFC框架间联立的方法

一:句柄关联性;

①接获取句柄或者窗口对象:Findwindow和FromHandle

②GetWindow加上FromHandle(hWnd);联立获取、

③获取主窗口句柄:

CWnd *wnd  = AfxGetMainWnd();

HWND hwnd =wnd->GetSafeHwnd();

④获取当前最上层窗口的句柄:

 HWND mainHwnd = ::GetForegroundWindow();//获取当前topmost的窗口句柄

⑤附加一些其它函数:

FindWindow  //这个估计会拖慢程序的运行速率

FindWindowEx

WindowFromPoint//获得当前鼠标光标位置的窗口HWND

GetActiveWindow 取当前活动窗口句柄

AfxGetMainWnd   取主窗口句柄//获得主框架窗口指针(任何时候都可以用,只要是MFC程序中)

GetForegroundWindow取前台窗口句柄

FindWindow寻找参数指定的窗口

EnumWindow枚举窗口

 

(二)MFC【MFC AppWizard(exe)框架】中各个框架间指针关联性:

一、一般的框架(this间的使用):<注意获取到的指针进行强制类型转换>

理解 m_pMainWnd, AfxGetApp(),AfxGetMainWnd() 的意义<最终归结首者>

 

1)获得Doc指针GetDocument();一个视只能有一个文档。

2)获得MainFrame指针CWinApp 中的 m_pMainWnd变量就是MainFrame的指针,也可以: AfxGetMainWnd

3) 获得MainFrame指针

CMainFrame*pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;

4) 获得View(已建立)指针

CMainFrame*pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;

CyouView*pView=(CyouView *)pMain->GetActiveView();

5) 获得当前文档指针

CDocument *pCurrentDoc =(CFrameWnd *)m_pMainWnd->GetActiveDocument();

6) 获得状态栏与工具栏指针

CStatusBar *pStatusBar=(CStatusBar*)AfxGetMainWnd()-

>GetDescendantWindow(AFX_IDW_STATUS_BAR);

CToolBar *pToolBar=(CtoolBar *)AfxGetMainWnd()->GetDescendantWindow

(AFX_IDW_TOOLBAR);

7) 如果框架中加入工具栏和状态栏变量还可以这样

(CMainFrame*)GetParent()->m_wndToolBar;

(CMainFrame*)GetParent()->m_wndStatusBar;

8) 在Mainframe获得菜单指针

CMenu*pMenu=m_pMainWnd->GetMenu();

9) 在任何类中获得应用程序类

AfxGetInstanceHandle得到句柄,AfxGetApp 得到指针

 

(三)MFC中句柄、指针、ID之间的转换使用

win32直接操作的是句柄HANDLE,每个句柄就对应windows窗口,而vc对HANDLE进行类封装,间接操作的都是HANDLE,现在句柄只是类的一个成员变量。

从句柄到指针

CWnd*pWnd=CWnd::FromHandle(hWnd); //a temporary CWnd object is

created //andattached.

pWnd->Attach(hWnd);//Attaches a Windows window to a CWnd object

从指针到句柄

HWNDhWnd=pWnd->GetSafeHandle(); //使用GetSafeHwnd函数取得程序所在窗口类的句柄

hWnd=pWnd->m_hWnd;

SDK编程中窗口ID,句柄,指针三者相互转换函数

ID--HANDLE--HWND三者之间的互相转换

id->句柄-----------hWnd =::GetDlgItem(hParentWnd,id);

id->指针-----------CWnd::GetDlgItem();

句柄->id-----------id = GetWindowLong(hWnd,GWL_ID);

句柄->指针--------CWnd*pWnd=CWnd::FromHandle(hWnd);

指针->ID----------id = GetWindowLong(pWnd->GetSafeHwnd,GWL_ID);

GetDlgCtrlID();

指针->句柄--------hWnd=cWnd.GetSafeHandle()or mywnd->m_hWnd;

HICON->ID--------HICONhIcon = AfxGetApp()->LoadIcon(nIconID);

                        HICON hIcon =LoadIcon(AfxGetApp()-

>m_hInstance,MAKEINTRESOURCE(nIconID));


7.Document(文档)、View(视图)、Frame(框架)、App(应用)之间相互访问


Document(文档)、View(视图)、Frame(框架)、App(应用)之间相互访问的 

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。
首先说明这四个类的执行顺序是App->Doc->Main->View
另外添加CDialog类获得各个指针的方法。
多文档的获取有点小区别,有时间也总结一下
[cpp]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. // App  
  2. void CSDIApp::OnApp()  
  3. {  
  4.     // App  
  5.     // Doc  
  6.     CDocument *pDoc = ((CFrameWndEx *)m_pMainWnd)->GetActiveDocument();  
  7.     // Main 成员变量m_pMainWnd  
  8.     CFrameWndEx *pMain = (CFrameWndEx *)AfxGetMainWnd();  
  9.     // View  
  10.     CView *pView = ((CFrameWndEx *)m_pMainWnd)->GetActiveView();  
  11. }  
  12. // Doc  
  13. CSDIDoc::CSDIDoc()  
  14. {  
  15.     // App  
  16.     CWinAppEx *pApp = (CWinAppEx *)AfxGetApp();  
  17.     // Doc  
  18.     // Main  
  19.     // Doc的创建先于Main  
  20.     // View  
  21.     // Doc的创建先于View  
  22. }  
  23. void CSDIDoc::OnDoc()  
  24. {  
  25.     // App  
  26.     // 同构造函数  
  27.     // Doc  
  28.     // Main  
  29.     CFrameWndEx *pMain = (CFrameWndEx *)AfxGetMainWnd();  
  30.     // View  
  31.     CView *pView= (CView *)pMain->GetActiveView();    //    POSITION pos = GetFirstViewPosition();       pView = GetNextView(pos); }  
  32. // Main  
  33. CMainFrame::CMainFrame()  
  34. {  
  35.     theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);  
  36.     // App  
  37.     CWinAppEx *pApp = (CWinAppEx *)AfxGetApp();  
  38.     // Doc  
  39.     // 构造函数里无法得到当前激活的Doc  
  40.     // Main  
  41.     // View  
  42.     // 构造函数里无法得到View指针,因为Main先于View创建。  
  43. }  
  44. void CMainFrame::OnMain()  
  45. {  
  46.     // App  
  47.     // 同构造函数  
  48.     // Doc  
  49.     CDocument *pDoc = (CDocument *)GetActiveDocument();  
  50.     // Main  
  51.     // View  
  52.     CView *pView = (CView *)GetActiveView();  
  53. }  
  54. // View  
  55. CSDIView::CSDIView()  
  56. {  
  57.     // App  
  58.     CWinAppEx *pApp = (CWinAppEx *)AfxGetApp();  
  59.     // Doc  
  60.     /* 无法在View的构造函数里得到Doc指针 
  61.        GetDocument();实际上是返回m_pDocument 
  62.        m_pDocument在OnCreate();里创建        */  
  63.     //CDocument *pDoc = GetDocument();  
  64.     // Main  
  65.     // 构造函数里无法得到MainFrame指针  
  66.     // CFrameWndEx *pMain = (CFrameWndEx *)pApp->m_pMainWnd;  
  67.     // View  
  68. }  
  69. void CSDIView::OnView()  
  70. {  
  71.     // App  
  72.     // 同构造函数  
  73.     // Doc  
  74.     CDocument *pDoc = GetDocument();  
  75.     // Main  
  76.     CFrameWndEx *pMain = (CFrameWndEx *)AfxGetMainWnd();  
  77.     // View  
  78. }  
  79. // Dlg  
  80. CDlg::CDlg(CWnd* pParent /*=NULL*/)  
  81.     : CDialog(CDlg::IDD, pParent)  
  82. {  
  83.     // App  
  84.     CWinAppEx *pApp = (CWinAppEx *)AfxGetApp();  
  85.     // Doc  
  86.     CDocument *pDoc = ((CFrameWndEx *)AfxGetMainWnd())->GetActiveDocument();  
  87.     // Main  
  88.     CFrameWndEx *pMain = (CFrameWndEx *)AfxGetMainWnd();  
  89.     // View  
  90.     CView *pView = ((CFrameWndEx *)AfxGetMainWnd())->GetActiveView();  
  91. }  

参考:
MFC中Doc,View,MainFrmae,App各指针的互相获取

  1)   在View中获得Doc指针  

  2)   在App中获得MainFrame指针  

  3)   在View中获得MainFrame指针  

  4)   获得View(已建立)指针  

  5)   获得当前文档指针  

  6)   获得状态栏与工具栏指针  

  7)   获得状态栏与工具栏变量  

  8)   在Mainframe获得菜单指针  

  9)   在任何类中获得应用程序类  

  10)   从文档类取得视图类的指针(1)  

  11)   在App中获得文档模板指针  

  12)   从文档模板获得文档类指针  

  13)   在文档类中获得文档模板指针  

  14)   从文档类取得视图类的指针(2)  

  15)   从一个视图类取得另一视图类的指针  

    
  VC中编程对于刚刚开始学习的同学,最大的障碍和问题就是消息机制和指针获取与操作。其实这些内容基本上是每本VC学习工具书上必讲的内容,而且通过MSDN很多问题都能解决。下面文字主要是个人在编程中指针使用的一些体会,说的不当的地方请指正。一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架,无论是多文档还是单文档,都存在指针获取和操作问题。下面这节内容主要是一般 的框架,然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先一般获得本类(视,文档,对话框都支持)实例指针this,用this的目的,主要可以通过类中的函数向其他类或者函数中发指针,以便于在非本类中操作和使用本类中的功能。

  1)   在View中获得Doc指针  

CYouSDIDoc   *pDoc=GetDocument();一个视只能有一个文档。  

   2)   在App中获得MainFrame指针  

  CWinApp   中的   m_pMainWnd变量就是MainFrame的指针   
  也可以:   CMainFrame   *pMain   =(CMainFrame   *)AfxGetMainWnd();

    3)   在View中获得MainFrame指针

  CMainFrame   *pMain=(CmaimFrame   *)AfxGetApp()->m_pMainWnd;

   4)   获得View(已建立)指针

  CMainFrame   *pMain=(CmaimFrame   *)AfxGetApp()->m_pMainWnd;   
  CyouView   *pView=(CyouView   *)pMain->GetActiveView();

  5)   获得当前文档指针

  CDocument   *   pCurrentDoc   =(CFrameWnd   *)m_pMainWnd->GetActiveDocument();

  6)   获得状态栏与工具栏指针

  CStatusBar   *   pStatusBar=(CStatusBar   *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);   
  CToolBar   *   pToolBar=(CtoolBar   *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);   

  7)   如果框架中加入工具栏和状态栏变量还可以这样    

  (CMainFrame   *)GetParent()->m_wndToolBar;   
  (CMainFrame   *)GetParent()->m_wndStatusBar;   

  8)   在Mainframe获得菜单指针

  CMenu   *pMenu=m_pMainWnd->GetMenu();

  9)   在任何类中获得应用程序类  

  用MFC全局函数AfxGetApp()获得。  

 10)   从文档类取得视图类的指针  

  从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题,我的体会   
  特别是文字处理CEditView当产生多个视图类时,这个功能是非常需要的。     
  CDocument类提供了两个函数用于视图类的定位:   
  GetFirstViewPosition()和GetNextView()     
  virtual   POSITION   GetFirstViewPosition()   const;   
  virtual   CView*   GetNextView(POSITION&   rPosition)   const;   
    
  注意:GetNextView()括号中的参数用的是引用方式,因此执行后值可能改变。   
  GetFirstViewPosition()用于返回第一个视图位置(返回的并非视图类指针,而是一   
  个POSITION类型值),GetNextView()有两个功能:返回下一个视图类的指针以及用   
  引用调用的方式来改变传入的POSITION类型参数的值。很明显,在Test程序中,只有   
  一个视图类,因此只需将这两个函数调用一次即可得到CTestView的指针如下(需定   
  义一个POSITION结构变量来辅助操作):     
  CTestView*   pTestView;   
  POSITION   pos=GetFirstViewPosition();   
  pTestView=GetNextView(pos);   
    
  这样,便可到了CTestView类的指针pTestView.执行完几句后,变量pos=NULL,因为没   
  有下一个视图类,自然也没有下一个视图类的POSITION.但是这几条语句太简单,不   
  具有太强的通用性和安全特征;当象前面说的那样,当要在多个视图为中返回某个指   
  定类的指针时,我们需要遍历所有视图类,直到找到指定类为止。判断一个类指针指   
  向的是否某个类的实例时,可用IsKindOf()成员函数时行检查,如:   
    pView->IsKindOf(RUNTIME_CLASS(CTestView));   
  即可检查pView所指是否是CTestView类。   
    
  有了以上基础,我们已经可以从文档类取得任何类的指针。为了方便,我们将其作   
  为一个文档类的成员函数,它有一个参数,表示要获得哪个类的指针。实现如下:

[cpp]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. CView*   CTestDoc::GetView(CRuntimeClass*   pClass)    
  2.   {    
  3.   CView*   pView;    
  4.   POSITION   pos=GetFirstViewPosition();    
  5.      
  6.   while(pos!=NULL){    
  7.   pView=GetNextView(pos);    
  8.   if(!pView->IsKindOf(pClass))    
  9.   break;    
  10.   }    
  11.      
  12.   if(!pView->IsKindOf(pClass)){    
  13.   AfxMessageBox("Connt   Locate   the   View./r/n   http://www.VCKBASE.com");    
  14.   return   NULL;    
  15.   }    
  16.      
  17.   return   pView;    
  18.   }  

其中用了两次视图类的成员函数IsKindOf()来判断,是因为退出while循环有三种可能:   
  1.pos为NULL,即已经不存在下一个视图类供操作;   
  2.pView已符合要求。   
    
  1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图   
  的位置同时返回当前视图指针,因此pos是pView的下一个视图类的POSITION,完全   
  有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一   
  个视图类时就如引。因此需采用两次判断。   
  使用该函数应遵循如下格式(以取得CTestView指针为例):   
  CTestView*   pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));   
  RUNTIME_CLASS是一个宏,可以简单地理解它的作用:将类的名字转化为   
  CRuntimeClass为指针。至于强制类型转换也是为了安全特性考虑的,因为从同一个   
  基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要,但能避免一   
  些可能出现的麻烦。   
    
  3.从一个视图类取得另一视图类的指针   综合1和2,很容易得出视图类之间互相获得   
  指针的方法:就是用文档类作中转,先用1的方法得到文档类的指针,再用2的方法,   
  以文档类的视图定位函数取得另一个视图类。同样,可以实现成一个函数:   
  (假设要从CTestAView中取得指向其它视图类的指针)

[cpp]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. CView*   CTestAView::GetView(CRuntimeClass*   pClass)    
  2.   {    
  3.   CTestDoc*   pDoc=(CTestDoc*)GetDocument();    
  4.   CView*   pView;    
  5.   POSITION   pos=pDoc->GetFirstViewPosition();    
  6.   while(pos!=NULL){    
  7.   pView=pDoc->GetNextView(pos);    
  8.   if(!pView->IsKindOf(pClass))    
  9.   break;    
  10.   }    
  11.   if(!pView->IsKindOf(pClass)){    
  12.   AfxMessageBox("Connt   Locate   the   View.");    
  13.   return   NULL;    
  14.   }    
  15.      
  16.   return   pView;    
  17.   }  

这个函数和2中的GetView()相比,一是多了第一句以取得文档类指针,二是在   
  GetFirstViewPosition()和GetNextView()前加上了文档类指针,以表示它们是文档   
  类成员函数。有了此函数;当要从CTestAView中取得CTestBView的指针时,只需如   
  下:CTestBView*   pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));
  11)对于单文档中也可以加入多个文档模板
但是一般的开发就使用MDI方式开发   
  多文档模板,其方法与上述视图的获取方法很接近,这里稍做解释,如果不清楚,   
  请查阅MSDN,(以下四个内容(11、12、13、14)来源:   
    
  可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板   
  的位置;利用该值来调用CWinApp::GetNextDocTemplate函数,获得第一个   
  CDocTemplate对象指针。   POSITION   GetFirstDocTemplate(   )   const;     
  CDocTemplate   *GetNextDocTemplate(   POSITION   &   pos   )   const;   
    
  第二个函数返回由pos   标识的文档模板。POSITION是MFC定义的一个用于迭代或对象   
  指针检索的值。通过这两个函数,应用程序可以遍历整个文档模板列表。如果被检索   
  的文档模板是模板列表中的最后一个,则pos参数被置为NULL。   
  12)一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文档的指针列表。    
  用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一   
  个文档的位置,并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与   
  模板相关的文档列表。函数原形为:   
  viaual   POSITION   GetFirstDocPosition(   )   const   =   0;     
  visual   CDocument   *GetNextDoc(POSITION   &   rPos)   const   =   0;       
    
  如果列表为空,则rPos被置为NULL.     
 13)在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。  
  函数原形如下:   CDocTemplate   *   GetDocTemplate   (   )   const;     
  如果该文档不属于文档模板管理,则返回值为NULL。     
  14)一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。  
  CDocument::AddView将一个视连接到文档上,将该视加入到文档相联系的视的列表   
  中,并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或   
  Window/Split的命令而将一个新创建的视的对象连接到文档上时,   MFC会自动调用   
  该函数,框架通过文档/视的结构将文档和视联系起来。当然,程序员也可以根据自   
  己的需要调用该函数。   
  Virtual   POSITION   GetFirstViewPosition(   )   const;     
  Virtual   CView   *   GetNextView(   POSITION   &rPosition)   cosnt;     
    
  应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的   
  列表中的第一个视的位置,并调用CDocument::GetNextView返回指定位置的视,并将   
  rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个   
  视,则将rPosition置为NULL.     
  15)从一个视图类取得另一视图类的指针  
  这个应用在多视的应用程序中很多见,一般如果自己在主程序或者主框架中做好变   
  量记号,也可以获得,还有比较通用的就是用文档类作中转,以文档类的视图


    访问对象

访问位置

访问实现

应用程序App

任何位置

     AfxGetApp();

     在要使用应用程序App的文件中加入:

extern CAApp theApp,然后直接使用全局的theApp变量。

主框架窗口

任何位置

AfxGetMainWnd();

AfxGetApp()->m_pMainWnd;

视图

框架类中

GetActiveView();  //当前的活动视图

文档类中

GetFirstViewPosition();//可以获取全部视图

GetNextView();

文档

文档类中

GetDocument()

文当模版类中

GetFirstDocPosition(); //该文档模版对应全部文档

GetNextDoc();

框架类中

GetActiveDocument(); //当前活动文当

子框架类(MDI中)

主框架类中

MDIGetActive();

GetActiveFrame();

视图类中

GetParentFrame();

文档模版

文档类中

GetDocTemplate();

应用程序App

GetFirstDocTemplatePosition();

GetNextDocTemplate();

说明:1)以上给出的都是方法,实际访问中可能还要进行以下简单的处理,如类型转换,循环遍历等;
         2)可能没有列举完所有可能位置的互访问,但可以通过他们的组合得到。


8.MFC类视图

Visual C++发展至今,MFC类库越来越强大,其基本层次结构如图所示,箭头的方向是从派生类指向基类。
               

MFC类基本层次结构



  其中,CObject类是MFC提供的绝大多数类的基类。该类完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。

  CCmdTarget类主要负责将系统事件(消息)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和派遣(调度)等工作,实现应用程序的对象之间协调运行。

  CWinApp类是应用程序的主线程类,它是从CWinThread类派生而来。CWinThread类用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。

  CDocument类是文档类,包含了应用程序在运行期间所用到的数据。

  CWnd类是一个通用的窗口类,用来提供Windows 中的所有通用特性。

  CView 是用于让用户通过窗口来访问文档以及负责文档内容的显示。

  CFrameWnd 类是从 CWnd 继承来的,并实现了标准的框架应用程序。

  CDialog 类用来控制对话框窗口。

  CMDIFrameWnd和CMDIChildWnd类分别用来多文档应用程序的主框架窗口和文档子窗口的显示和管理。
CMiniFrameWnd类是一种简化的框架窗口,它没有最大化和最小化窗口按钮,也没有窗口系统菜单,一般很少用到它。


http://www.cppblog.com/andxie99/archive/2008/06/04/9747.html
整理资料,看到几张MFC的类层次结构图。也来看看MFC的发展吧:

9.FMC消息映射宏概念区分

还有消息映射 消息反射之分。

  ①、映射机制的原理 Windows 下的程序包括 Windows 系统都是基于消息机制的。 MFC消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个消息和消息响应函数的静态对照表,即消息映射表; 在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中; 当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就可以知道该类能否处理此消息; 如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数!


②、一般情况下,一个MFC的消息映射在程序中有三处相关信息:1》消息响应函数的声明 2》消息响应函数实现 3》用来关联消息和消息响应函数的宏 具体见示例代码……更为详细的讲解参见《深入浅出MFC 第二版 简体中文版》 - 侯杰:http://www.cctry.com/thread-192-1-1.html
③、针对不同的 Windows 消息,MFC提供了不同的消息映

射宏,主要分为如下六类:


1、Windows 消息映射宏 Windows 消息映射宏用于处理普通的窗口消息。此类消息映射宏前缀为“ON_WM_”,并且没有参数;


2、命令消息映射宏 命令消息 WM_COMMAND 是一种特殊的窗口消息,它从一个窗口发送到另一个窗口,以处理来自用户的请求,是 ON_COMMAND 宏和 ON_COMMAND_RANGE 宏;


3、控件通知消息映射宏 控件通知消息是指控件窗口发送到其父窗口的消息,其消息映射宏为 ON_CONTROL 和 ON_CONTROL_RANGE,有时在程序中并不见 ON_CONTROL 宏,而见 ON_BN_CLICKED 宏, 其实 ON_CONTROL 宏派生出许多的映射宏,包括 ON_BN_CLICKED 宏等;


4、控件通知消息映射宏 控件通知消息映射宏处理的窗口消息有 WM_COMMAND,WM_NOTIFY,其消息映射宏有 ON_NOTIFY 和 ON_NOTIFY_RANGE;


5、反射消息映射宏 反射消息是指子窗口向父窗口发送的通知消息或控件通知消息,父窗口将该消息转化为相应的反射消息发送给子窗口优先处理。处理窗口消息 WM_NOTIFY+WM_REFLECT_BASE 的宏是 ON_NOTIFY_REFLECT,处理窗口消息 WM_COMMAND+WM_REFLECT_BASE 的宏是 ON_CONTROL_REFLECT, 还有其他的反射消息宏,具体请参考MDSN。


6、扩展消息映射宏 有 ON_COMMAND | ON_COMMAND_RANGE | ON_NOTIFY | ON_NOTIFY_RANGE ……

④、自定义消息的发送与响应:

1、自定义消息号:#define WM_CCTRY_MSG (WM_USER+100)

2、在头文件中添加消息响应函数的声明:afx_msg LRESULT OnCcTryMsg(WPARAM wParam, LPARAM lParam);

3、在CPP文件中添加消息响应函数的实现: LRESULT CXXXDlg::OnCcTryMsg(WPARAM wParam, LPARAM lParam) { //相关代码; }

4、在 BEGIN_MESSAGE_MAP 与 END_MESSAGE_MAP 之间加入消息的映射代码:ON_MESSAGE(WM_CCTRY_MSG, &CDlgTestDlg::OnCcTryMsg)

5、消息的发送:

10.模态对话框的创建与销毁.

原文链接:http://www.cnblogs.com/likebeta/archive/2011/11/17/2253150.html

//尊重原作者,转载请注明出处

要点提醒
销毁一个窗口对象:
删除窗口最直接方法是调用CWnd::DestroyWindow或::DestroyWindow,前者封装了后者的功能。前者不仅会调用后者,而且会使成员m_hWnd保存的HWND无效(NULL)。

细节解释:
如果DestroyWindow删除的是一个父窗口或拥有者窗口,则该函数会先自动删除所有的子窗口或被拥有者,然后再删除父窗口或拥有者。在一般情况下,在程序中不必直接调用DestroyWindow来删除窗口,因为MFC会自动调用DestroyWindow来删除窗口。例如,当用户退出应用程序时,会产生WM_CLOSE消息,该消息会导致MFC自动调用CWnd::DestroyWindow来删除主框架窗口,当用户在对话框内按了OK或Cancel按钮时,MFC会自动调用CWnd::DestroyWindow来删除对话框及其控件。 
窗口对象本身的删除则根据对象创建方式的不同,分为两种情况。在MFC编程中,会使用大量的窗口对象,有些窗口对象以变量的形式嵌入在别的对象内或以局部变量的形式创建在堆栈上,有些则用new操作符创建在堆中。对于一个以变量形式创建的窗口对象,程序员不必关心它的删除问题,因为该对象的生命期总是有限的,若该对象是某个对象的成员变量,它会随着父对象的消失而消失,若该对象是一个局部变量,那么它会在函数返回时被清除。

初学者困惑:
对于一个在堆中动态创建的窗口对象,其生命期却是任意长的。初学者在学习C++编程时,对new操作符的使用往往不太踏实,因为用new在堆中创建对象,就不能忘记用delete删除对象。读者在学习MFC的例程时,可能会产生这样的疑问,为什么有些程序用new创建了一个窗口对象,却未显式的用delete来删除它呢?问题的答案就是有些MFC窗口对象具有自动清除的功能。

注意:
不具有自动清除功能的窗口类如下所示。这些窗口对象通常是以变量的形式创建的,无需自动清除功能。 
   所有标准的Windows控件类。 
   从CWnd类直接派生出来的子窗口对象(如用户定制的控件)。 
   切分窗口类CSplitterWnd。 
   缺省的控制条类(包括工具条、状态条和对话条)。 
   模态对话框类。 
   具有自动清除功能的窗口类如下所示,这些窗口对象通常是在堆中创建的。 
   主框架窗口类(直接或间接从CFrameWnd类派生)。 
   视图类(直接或间接从CView类派生)。



综上概括:
综上所述,对于MFC窗口类及其派生类来说,在程序中一般不必显式删除窗口对象。也就是说,既不必调用DestroyWindow来删除窗口对象封装的窗口,也不必显式地用delete操作符来删除窗口对象本身。只要保证非自动清除的窗口对象是以变量的形式创建的,自动清除的窗口对象是在堆中创建的,MFC的运行机制就可以保证窗口对象的彻底删除。如果需要手工删除窗口对象,则应该先调用相应的函数(CWnd::DestroyWindow)删除窗口,然后再删除窗口对象.对于以变量形式创建的窗口对象,窗口对象的删除是框架自动完成的.对于在堆中动态创建了的非自动清除的窗口对象,必须在窗口被删除后,显式地调用delete来删除对象(一般在拥有者或父窗口的析构函数中进行).对于具有自动清除功能的窗口对象,只需调用CWnd::DestroyWindow即可删除窗口和窗口对象。注意,对于在堆中创建的窗口对象,不要在窗口还未关闭的情况下就用delete操作符来删除窗口对象. 
提示:在非模态对话框的OnCancel函数中可以不调用CWnd::DestroyWindow,取而代之的是调用CWnd::ShowWindow(SW_HIDE)来隐藏对话框.在下次打开对话框时就不必调用Create了,只需调用CWnd::ShowWindow(SW_SHOW)来显示对话框.这样做的好处在于对话框中的数据可以保存下来,供以后使用.由于拥有者窗口在被关闭时会调用DestroyWindow删除每一个所属窗口,故只要非模态对话框是自动清除的,程序员就不必担心对话框对象的删除问题.


MFC应用程序中处理消息的顺序
1.AfxWndProc() 该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc
2.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消息,发送此消息以允许改变对


11.OLE接口详解

概要

OLE 是一套实施的服务、 自定义这些服务的机制和安装自定义服务进行各种协议的机制。 每个 OLE API 函数和每个当前定义的接口 (即,在那些传送 OLE 技术) 具有在此框架中的目的。 下面列出了 API 函数和接口,以及它们的用途,分为以下功能组:

  • 常规
  • 初始化和内存管理
  • 远程处理
  • 自定义服务
  • 服务注册
  • DLL 服务器管理
  • 杂项 COM 函数
  • 命名 (名字对象)
  • 结构化的存储
  • 永久对象
  • 每个事件的通知
  • 统一数据传输
  • 可查看对象
  • 标准类型
  • OLE 剪贴板
  • OLE 拖放
  • 类型库
  • OLE 自动化
  • OLE 属性页
  • OLE 文档: 常规
  • OLE 文档: 处理程序和缓存
  • OLE 文档: 嵌入
  • OLE 文档: 链接
  • OLE 文档: 就地激活
  • OLE 文档: OLE 1 兼容性
  • OLE 控件

更多信息

下面的列表有助于阐明为何存在不同的 Api 和接口,并包括以下信息:
函数: < OLE API 函数和接口的列表 >
目的: < 用途说明 >
注意: OLE UI 库中的函数集合不包括这一次。 此外缺少一些最近添加的接口。

常规

函数: lUnknown
目的: 控制对象生存期,接口协商。 普遍而不考虑实施任何组件。 QueryInterface 公开传入接口。

函数: IEnum
目的: 枚举的各种类型的列表。 在许多情况下,整个 OLE 中使用。

函数: IProvideClassInfo
目的: 公开有关对象的传入和传出接口的类型信息。

函数: IConnectionPointContainer,IEnumConnectionPoints,IConnectionPoint IEnumConnections
目的: 公开对象的输出接口。

初始化和内存管理

函数: CoBuildVersion OleBuildVersion
目的: 检查 OLE 库的版本号。

函数: IMalloc
目的: 任务内存分配。

函数: CoInitialize,CoUninitialize,OleInitialize OleUninitialize
目的: 初始化/Uninitialize COM/OLE 库和 OLE-提供的安装任务 (大多数 OLE 实现还允许安装自定义分配器) 的分配器。

函数: CoCreateStandardMalloc
目的: 访问标准任务内存分配器。

函数: CoGetMalloc
目的: 访问当前已安装的任务分配器。

远程处理

函数: IExternalConnection
目的: 通知-连接/断开连接从远程进程。

函数: CoLockObjectExternal
目的: 锁定远程对象实现。

函数: CoDisconnectObject
目的: 强制断开任何远程连接。

函数: IMarshal
目的: 标准封送处理 (OLE impl) ; 此自定义封送处理 (自定义实现)。

函数: CoGetStandardMarshal
目的: 访问标准实现 IMarshal。

函数: IStdMarshalInfo
目的: 支持自定义接口。

函数: CoMarshalHresult、 CoUnmarshalHresult、 CoMarshalInterface、 CoUnmarshalInterface、 CoReleaseMarshalData
目的: 标准和自定义封送的帮助。 例如,CoMarshalInterface,总是调用时需要创建新对象的接口指针的远程服务器端处理支持的任何对象。 CoUnmarshalInterface 创建的客户端,以匹配。

函数: CoIsHandlerConnected
若要确定是否已连接到远程进程的进程内组件的用途: 帮助器。

自定义接口函数:
目的: 安装自定义 IMessageFilter 实现。

函数: IMessageFilter
目的: OLE 1 容器文档相兼容的 Helper 函数。

函数: CoRegisterMessageFilter
目的: 并发处理接口的管理。 远程处理时,始终安装默认实现。

自定义服务

函数: CoCreateInstance
目的: 访问自定义组件实现给定的 CLSID。

函数: IClassFactory [2]
目的: 创建自定义组件基于 CLSID。

函数: CoGetClassObject
提供 CLSID 目的: 访问自定义类工厂实现。

函数: DllGetClassObject
目的: 公开 DLL 中的自定义类工厂实现。

函数: CoRegisterClassObject CoRevokeClassObject
目的: 安装/删除自定义类工厂实现。

服务注册

函数: CoCreateGuid,IsEqualGUID,IsEqualIID IsEqualCLSID
目的: 帮助创建和 Guid 的比较。

函数: DllRegisterServer DllUnregisterServer
目的: 公开从 DLL 服务器模块的自行注册功能。

函数: CoGetTreatAsClass、 CoTreatAsClass、 OleDoAutoConvert、 OleGetAutoConvert、 OleSetAutoConvert、 GetConvertStg、 SetConvertStg
目的: 每个仿真的转换操作 (只有自定义是描述哪些类的注册表信息互换)。

DLL 服务器管理

函数: DllCanUnloadNow
目的: 控制 DLL 服务器卸载。

函数: CoLoadLibrary,CoFreeLibrary,CoFreeAllLibraries CoFreeUnusedLibraries
目的: 加载和卸载进程内服务器模块。

杂项 COM 函数

函数: CLSIDFrom [ProgID | 字符串] [ProgID | 字符串] FromCLSID,IIDFromString,StringFromIID StringFromGUID2
目的: Helper 函数 Guid、 字符串和 ProgIDs 之间的转换。

函数: CoGetCurrentProcess
目的: 杂项帮助器。

函数: CoDosDateTimeToFileTime,CoFileTimeToDosDateTime,CoFileTimeNow
日期/时间转换的目的: 杂项 helper 函数。 (更适合为 Win32 API)。

函数: IsValidIid,IsValidInterface,IdValidPtrIn IsValidPtrOut
目的: 杂项验证函数 (仅限于 16 位)。

命名 (名字对象)

函数: IMoniker
目的: 公开名字对象的功能。 OLE 提供了五个名字对象实现的 (五个不同的类)。 通过对象创建函数或自定义的 API,可以公开自定义实现。

函数: BindMoniker
IMoniker::BindToObject 的用途: 包装。

函数: CreateFileMoniker、 CreateItemMoniker、 CreateAntiMoniker、 CreatePointerMoniker、 CreateGenericComposite
目的: 访问 OLE 标准名字对象实现的。

函数: IParseDisplayName
目的: 实现一个自定义的对象,以分析为标记对象、 标准或自定义的用户可读的显示名称上。

函数: IOleContainer IOleItemContainer
目的: 通常与 OLE 文档,而这些接口上实现包含项目,并且需要绑定项的名字对象的对象。

函数: IBindCtx
目的: 实现 OLE 标准"绑定上下文"对象上。

函数: CreateBindCtx
目的: 实例化返回 IBindCtx 指针绑定上下文对象。

函数: IRunningObjectTable
目的: 从公开 OLE 实现"运行对象表"的服务。 没有自定义项。

函数: GetRunningObjectTable
目的: 访问运行对象表。

函数: MkParseDisplayName
目的: 将字符串转换为包含可确定其实现的 IParseDisplayName 使用的智能标记。

函数: MonikerRelativePathTo MonikerCommonPrefixWith
目的: 帮助者操作文件名字对象来创建使用 IMoniker::RelativePathTo 和 IMoniker::CommonPrefixWith 的绝对和相对路径。

结构化的存储

函数: IStorage
目的: 公开存储对象功能 (目录)。

函数: IStream
目的: 公开流对象功能 (文件)。

函数: IRootStorage
目的: 控制连接到复合文件中的 IStorage 的基础文件。

函数: ILockBytes
目的: 自定义复合文件中的底层存储介质。

函数: StgCreateDocfile StgOpenStorage
目的: 创建或打开使用默认的基于文件的 ILockBytes 实现 OLE 的复合文件 (IStorage/IRootStorage) 实现。

函数: StgCreateDocfileOnILockBytes StgOpenStorageOnILockBytes
目的: 创建或打开使用自定义的 ILockBytes 实现 OLE 的复合文件 (IStorage/IRootStorage) 实现。

函数: StgIsStorageFile StgIsStorageILockBytes
目的: 检查文件是否为 ILockBytes 的默认实现或自定义实现的复合文件。

函数: CreateILockBytesOnHGlobal GetHGlobalFromILockBytes
目的: 访问基于内存的 ILockBytes 实现。

函数: CreateStreamOnHGlobal,GetHGlobalFromStream。
目的: 访问基于内存的 IStream 实施。

函数: [读取 | 编写] 类 [Stg | Stm] [读取 | 写] FmtUserTypeStg GetClassFile
目的: 检索或保存到存储或流的 CLSID、 数据格式和用户类型信息。

函数: StgSetTimes
目的: Helper 函数来处理复合文件时间戳。

永久对象

函数: IPersist,IPersistFile,IPersist-存储,Μ [初始]
目的: 从基于存储模型的持久对象公开: 文件-基于、 基于 IStorage、 IStream 基于 (有或没有初始化)。

每个事件的通知

函数: IAdviseSink [2]
目的: 接收通知的数据更改,更改视图、 复合文档对象的更改。

函数: IPropertyNotifySink
目的: 接收属性更改和控制可重写更改的通知。

函数: 事件集
目的: 接口对象所定义的、 由外部事件接收器。

统一数据传输

IDataObject,(IAdviseSink),IEnumFORMATETC 函数:
目的: 公开交换格式的数据结构和通知数据更改的通知接收器的能力。

函数: OleDuplicateData
目的: Helper 函数,用于复制的数据结构。

函数: ReleaseStgMedium
目的: 帮助者释放数据结构。

可查看对象

函数: IViewObject [2],(IAdviseSink)
目的: 公开到设备上下文中绘制可视演示文稿并通知视图更改的通知接收器的能力。

函数: OleDraw
目的: IViewObject::Draw 的简单包装。

函数: OleGetIconOfFile,OleMetafilePictFromIconAnd 标签,OleGetIconOfClass
目的: Helper 函数,用于操作对象的图标视图。

函数: OleTranslateColor
目的: 帮助者 COLORREF 和 OLE_COLOR 类型之间转换。

标准类型

函数: IFont IFontDisp
目的: 公开标准字体对象实现 (OLE 控件)。

函数: OleCreateFontIndirect
目的: 访问标准字体对象实现。

函数: IPicture IPictureDisp
目的: 公开标准图片对象实现 (OLE 控件)。

函数: OleCreatePictureIndirect
目的: 访问标准图片对象实现。

函数: OleLoadPicture
目的: 从流信息创建图片对象。

函数: OleIconToCursor
目的: Helper 函数以将转变为游标的简单的 Win32 API 的图标基于和拖放 (没有 OLE 拖放)。 >

OLE 剪贴板

函数: OleSetClipboard,OleGetClipboard,OleFlushClipboard OleIsCurrentClipboard
剪贴板处理服务通过 IDataObject 的用途: API。 除所涉及的任何 IDataObject 实现的任何自定义项。

OLE 拖放功能

函数: IDropSource
目的: 公开在拖放操作中的源端功能。

函数: IDropTarget
目的: 公开在拖放操作中的目标端功能。

函数: DoDragDrop
目的: 安装 IDropSource (和 IDataObject) 开始拖放操作的实现。

函数: RegisterDragDrop RevokeDragDrop
目的: 安装/卸载拖放目标实现。 拖放目标只公开到 DoDragDrop。

类型库

函数: ITypeLib ITypeInfo
目的: 标准 OLE 实现类型库结构中导航。

函数: ITypeComp
要绑定到更高效的方法,用于编译器类型库中定义的接口函数的用途: 标准 OLE 实现。

函数: LHashValOfName [Sys]
目的: 创建在 ITypeComp 函数中使用的哈希值。

函数: LoadTypeLib、 LoadRegTypeLib、 LoadTypeLibFromResource、 RegisterTypeLib、 QueryPathOfRegTypeLib
目的: 用于注册和加载类型库的帮助。 正在加载类型库表示实例化类型库的对象与 ITypeLib 在其上。 换句话说,负载 [标准] 的类型库 [FromResource] 访问标准的 ITypeLib 实现。

函数: CreateTypeLib
目的: 创建新的类型库 (而不是加载一个现有)。 类型库实现 ICreateTypeLib。 通常使用从类型库编译器。

函数: ICreateTypeLib ICreateTypeInfo
目的: 实现 OLE 用于创建类型库中。 从类型库编译器使用。

函数: CreateDispTypeInfo
目的: 创建具有 ITypeInfo INTERFACEDATA 结构所基于的类型信息对象。

函数: CompareStringA,LCMap StringA,GetLocaleInfoA,Get StringTypeA,GetSystemDefault-[LangID | LCID] GetUser 默认 [LangID | LCID]
目的: Helper 函数使用 OLE 自动化中的特定于区域设置的信息。 它们主要用于 Win16 平台为相同的功能是标准的 Win32 API 的一部分。

OLE 自动化

函数: IDispatch IEnumVARIANT
目的: 公开方法和属性,通过一种机制,派单 (DISPID) 以及"集合"。

函数: CreateStdDispatch
目的: 将自定义接口安装到标准的 IDispatch 实现。 换句话说,访问内部取决于自定义接口实现标准 IDispatch。

函数: DispGetIDOfNames,DispGetParams,DispInvoke
目的: 帮助器功能的直接实现或 IDispatch 的使用。

函数: RegisterActiveObject,RevokeActiveObject,GetActiveObject
目的: Helper 函数以注册自动化对象,如运行和运行的访问对象。 基本上包装运行对象表。

函数: SafeArray-AccessData、 AllocData、 AllocDescriptor,复制、 创建、 销毁,DestroyData、 DestroyDescriptor、 GetDim、 GetElement、 GetElemSize、 GetLBound、 GetUBound、 锁定、 PutElement、 Redim、 UnAccessData,解除锁定
目的: 通过 IDispatch 的 Helper 函数用于操作数组传递。

Sys-AllocString、 AllocStringLen、 FreeString、 ReAllocString、 ReAllocStringLen、 StringLen 函数:
目的: Helper 函数以操纵 BSTR 类型。

函数: [Ex] 的 variant 类型的值的误差清除,请复制、 CopyInf、 初始化、 TimeToDosDateTime ; () DosDateTimeToVarantTime
目的: Helper 函数以操纵变量传入的变量结构如类型转换和复制)。

OLE 属性页

函数: OleCreatePropertyFrame-[间接]
目的: 实现 IPropertyPageSite 的属性页框架的访问标准实现。

函数: IPropertyPageSite
目的: 公开的功能作为属性页框架。

函数: ISpecifyPropertyPages
目的: 公开的对象的属性页 (它们是单独的对象) 的 Clsid。

函数: IPropertyPage [2]
目的: 公开属性页的功能。

函数: IPerPropertyBrowsing
目的: 公开操纵单个属性的能力。

OLE 文档: 常规

函数: OleRegGetUserType,OleRegGetMiscStatus,OleRegEnumFormatEtc OleRegEnumVerbs
目的: 对于默认注册表处理 Helper 函数 (主要是 OLE 文档)。

函数: IRunnableObject
目的: 当将一个对象的通知之间加载并正在运行。

函数: OleIsRunning、 OleLockRunning、 OleRun、 OleNoteObjectVisible、 OleSetContainedObject
在复合文档中运行对象的控件的用途: 帮助。 其中的大部分功能调用 IRunnableObject 成员。

函数: IOleAdviseHolder
目的: Helper 函数,用于管理从复合文档对象实现内的 IAdviseSink 指针。

函数: CreateOleAdviseHolder
目的: 访问 IOleAdviseHolder 对象的 OLE 实现。 没有自定义项。

函数: OleLoad,OleLoadFromStream,OleSave OleSaveToStream
目的: 函数,以加载和保存在 IStorage 或 IStream 实例中的复合文档对象。 IPersistStorage 和 Μ 呼叫的包装。

函数: OleCreateStaticFromData
目的: 访问的静态对象的 OLE 实现。

OLE 文档: 处理程序和缓存

函数: OleCreateDefaultHandler OleCreateEmbeddingHelper
目的: 访问 OLE 实施的默认处理程序或"嵌入帮助器"(cut-rate 的默认处理程序相同进程对象)。

函数: IOleCache [2]
目的: 实现由 OLE 提供的默认情况下,进程内处理程序和使用可自定义的复合文档中的服务器。

函数: CreateDataCache
目的: 访问 OLE 的数据高速缓存的实现 (服务)。 缓存对象实现的接口包括 [2] IOleCache、 IOleCacheControl、 IDataObject、 IViewObject [2] 和 IPersistStorage 的数字。

函数: IOleCacheControl
目的: 实现在 OLE 的默认处理程序来访问远程服务器的 IDataObject 实现。 在 OLE 文档中使用。

OLE 文档: 嵌入

函数: IOleObject
目的: 公开复合文档对象功能。

函数: IOleClientSite
目的: 提供容器端信息和复合文档对象的函数。

函数: OleCreate,OleCreate FromData,OleCreateFromFile ; OleQueryCreateFromData
目的: 访问嵌入的复合文档对象,具体取决于所在的源信息的自定义实现)。 OleQueryCreate FromData 检查 OleCreateFromData 将起作用。

OLE 文档: 链接

函数: IOleLink
目的: 从链接的复合文档对象 (通常来自 OLE 的默认处理程序) 的过程中实现公开。

函数: OleCreateLink,OleCreateLinkFromData,OleCreateLinkToFile ; OleQueryCreateLinkFromData
目的: 访问链接的复合文档对象,具体取决于所在的源信息的自定义实现)。 检查是否起作用 OleCreateLinkFromData 的 OleQueryCreate LinkFromDat。

函数: IOleContainer IOleItemContainer
目的: 枚举一般容器内的对象 (通常为复合文档容器,但不是一定)。 IOleItemContainer 支持额外的步骤来绑定项名字对象。

OLE 文档: 就地激活

函数: IOleInPlaceObject IOleInPlaceActiveObject
目的: 公开就地激活模式支持 (从 IOleWindow 派生接口) 的对象端功能。

函数: IOleInPlaceFrame,IOleInPlaceUIWindow,IOleInPlaceSite
目的: 公开就地激活模式支持 (从 IOleWindow 派生接口) 的容器端功能。

函数: OleCreateMenuDescriptor,OleDestroyMenuDescriptor,OleSetMenuDescriptor OleTranslateAccelerator
就地激活的目的: 提供 OLE helper 函数。

OLE 文档: OLE 1 兼容性

函数: CoIsOle1Class
目的: 帮助者检查类是 OLE 1 复合文档对象。

函数: OleConvertIStorageToOLE 流 [Ex],OleConvertOLE STREAMToIStorage [Ex]
目的: Helper 函数提供与 OLE 1 兼容容器的复合文档。

OLE 控件

函数: IOleControl
处理键盘助记键和环境属性的更改之间的容器的目的: 公开 OLE 控件细节。

函数: IOleControlSite
OLE 控件的用途: 公开 OLE 控件容器细节。

函数: ISimpleFrameSite
目的: 公开 OLE 控件只是一个可视图文筛选邮件转到其中的控件提供的一组控件 (如单选按钮) 的组行为的其他控件的一组。

原文转载自:http://blog.csdn.net/ljmwork/article/details/7714920

12.MFC控件关联变量

重要的话写在前面:

        DDX_Text(pDX, IDC_EDIT4, iNumber);

        DDX_Control(pDX, IDC_EDOBJ, m_Edobj);


注意宏不同决定作用不同,前者将数据与对象关联,以便调用updata.后者将控件本身与对象关联,以便直接通过该变量操控控价本身.

控件关联变量的方法:

在控件上右键-->添加变量->将类别改成Value(默认是Control) ->选择变量类型->取一个变量名->根据类型会提示相关项可输入

如下图

点击完成(注意这里的访问, 变量类型和变量名之所以是灰色的, 是因为我这是第二次打开)

将会在三处生成代码

1. 头文件 访问所选位置(这里是public) int iNumber;

2. 类初始化此变量

3.DoDataExchange 出生成相关代码

   DDX_Text(pDX, IDC_EDIT4, iNumber);
   DDV_MinMaxInt(pDX, iNumber, 0, 50);

 

现在我们在改变变量的时候可以这样做, 以便它和控件实时关联

UpdateData(TURE);

iNumber = 10;

UpdateData(FALSE);

 

===================

以上是以CEdit为例, 其它控件方法大同小异


原文转载自:http://blog.csdn.NET/love3s/article/details/7622349


13.注册系统热键<不能Ctrl + p>

CHotKeyCtrl m_HotKey; 有这个控件,并且关联控件变量

提取码.并实现注册.

WORD wvk,wmod;
m_HotKey.GetHotKey(wvk,wmod);
BOOL result=RegisterHotKey(this->GetSafeHwnd(),HOTKEY_MES,wmod,wvk);

窗口响应热键消息:

ON_MESSAGE(WM_HOTKEY,OnHotKey)

HRESULT CHotKeyDlg::OnHotKey(WPARAM wParam, LPARAM lParam)
{
if(HOTKEY_MES == (int)wParam)
{
MessageBox("热键被按下");
}
return S_OK;
}


14.多文档应用

. 文档的基本功能:

    1) 文档就是程序数据的一种抽象表示,可以表示数据库连接资源、文本文字等任何形式的数据;

    2) 文档对象主要为视图提供公用成员函数,使其可以访问文档的数据,但所有的数据处理都由文档对象自己完成;


2. 文档类的主要操作:

    1) 操作和可覆盖函数:在MFC文献中,操作被描述为非虚拟类的成员函数,而可覆盖函数即虚函数;

    2) const String& CDocument::GetPathName() const; // 获取当前文档的绝对路径,如果文档还未命名则返回空

    3) const String& CDocument::GetTitle() const; // 获取当前文档的标题,就是去掉路径和后缀,同样,如果文档还未命名则返回空

    4) virtual BOOL CDocument::IsModified(); // 判断文档再最近一次保存之后是否被修改过

    5) virtual void CDocument::SetModifiedFlag(BOOL bModified = TRUE); // 直接设置文档是否被修改的标志

!!IsModified和SetModifiedFlag可以实现自动化的保存更改提示,你只要通过这两个函数设置了修改标志就可以让MFC在程序关闭时提示用户该文档是否修改过,是否要保存更改,无须自己去实现弹出提示框提示保存更改;

    6) void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL);

!!该函数将会更新重画相应视图(内部调用了具体视图的OnUpdate函数);

         i. pSender表示具体要更新的视图,如果为NULL表示与之相关的所有视图都要更新;

         ii. lHint和pHint表示和更新有关的信息,这里暂时用不到,因此就直接使用默认值即可;

         iii. 即使是单视图的应用程序也可以调用该函数来更新当前视图;

    7) 通过GetFirstViewPosition和GetNextView来迭代程序的所有视图:

         i. virtual POSITION CDocument::GetFirstViewPosition() const; // 将返回与当前文档相关联的第一个视图的位置指针

         ii. virtual CView* CDocument::GetNextView(POSITION& rPosition) const; // 根据位置信息获取下一个视图的指针

         iii. UpdateAllViews就是使用这两个函数来迭代更新所有视图的:

[cpp]  view plain  copy
  1. POSITION pos = GetFirstViewPosition();  
  2. while (pos)  
  3. {  
  4.     CView* pView = GetNextView(pos);  
  5.     .  
  6.     .  
  7.     .  
  8.     pView->OnUpdate();  
  9. }  

!!OnUpdate是CView的保护性成员,但是在CDocument中却可以自由访问该程序,原因是CDocument在底层被声明为CView的友元!!


3. 文档类的可覆盖函数:

    1) OnNewDocument和OnOpenDocument:

         i. 前者是响应File菜单的New菜单项用来创建新的文档,后者响应File菜单的Open菜单项来从磁盘中打开一个已存在的文档;

         ii. 两者的主要目的都是为了执行一些专门的初始化(对文档对象中的数据成员执行一些特殊的初始化),那么问题就来了!文档对象不是有自己的构造函数吗?为啥不直接用构造函数来初始化呢?

!!这里先要理解一下永久数据和非永久数据的概念:

        a. 永久数据:就是那些要保存在磁盘还要读出的那些数据(一般要通过串行化来实现此类数据的交换);

        b. 非永久数据:无须保存在磁盘里的一些辅助行数据,比如一些标志等(判断文档是否被修改,某个逻辑判断的标志)以及其它数据(数据库连接资源等);

!!构造函数一般用来初始化一些非永久数据,而通常是在创建文档和打开文档时对对象中的一些永久数据进行特定的初始化,因此OnNewDocument和OnOpenDocument覆盖得比较多;

         iii. 通常New比Open覆盖的频率更高,以为Open会在基类Open中间接调用Serialize串行化来初始永久数据,而New是创建一个空的新文档,需要手动初始化数据的需求更加大;

         iv. 函数原型:

              a. virtual BOOL CDocument::OnNewDocument();

              b. virtual BOOL CDocument::OnOpenDocument(LPCTSRT lpszPathName);

!!!使用Wizard创建文档/视图结构程序时,MFC会提供这两个函数的默认实现,以方便用户覆盖(因为这两个函数覆盖得实在太频繁了),覆盖时一定要注意调用基类的响应函数!!

    2) DeleteContents函数:

         i. 该函数在文档被打开和关闭时调用,用来删除当前文档对象中已有的数据;

         ii. 不能理解的是为何要在打开之前也要删除文档对象中的内容呢?因为通常一个程序在打开一个文档并处理完后可能会再打开另一个文档,那么此时程序应该显示新文档中的内容,那么前一个文档中的内容就理所当然的应该被删除了!

         iii. 原型:virtual void CDocument::DeleteContents();

         iv. 通常需要覆盖该函数来删除一些特殊的资源,比如数据库连接资源等;

    3) Serialize函数:

         i. 用来串行化文档的永久数据;

         ii. 对于可串行化数据直接使用<<和>>串行化;

         iii. 对于不能串行化的数据可以使用CArchive的Read和Write或者ReadString、WriteString读写磁盘;

         iv. 如果还不行就直接使用CArchive的GetFile获取文件的CFile指针直接与文件进行底层的交互;

!!一般所有对象都可以进行串行化,那行没有默认串行化的类可以自己实现串行化协议使之串行化;


!!其它不常覆盖的函数:

        a. OnCloseDocument:文档关闭时调用;

        b. OnSaveDocument:文档保存时调用;

        c. SaveModified:在文档未保存被关闭时调用,用以询问用户是否要做保存修改;

        d. ReportSaveLoadException:串行化发生错误时调用;


15.MFC隐藏模态对话框、

 

 博主写项目发现,创建对话框工程时候,想在OnInitDialog去showwindow(sw_hide)隐藏窗口、但是发现无效。于是变研究MFC框架、改写相关内容合理的解决了这一问题。废话不多说,上方法:



并在下方添加如下代码:

dlg.Create(IDD_BANKSYSTEM_DIALOG,NULL);
dlg.ShowWindow(SW_HIDE);
MSG msg;


while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}



方法:在app类中的initinstance中进行横向箭头修改。、因为默认创建工程创建的是模态对话框,将其修改为创建非模态对话框,并补充消息环、完美解决。


16.Windows下实现程序托盘效果.

/*
隐藏任务栏代码讲解:实际上对任务栏操作就是对Shell_NotifyIcon函数的调用操作任务栏,并调用showwindow隐藏窗体.
        1.因为要自适应通用操作,所以才封装了函数.
        2.添加任务栏图标为,Shell_NotifyIcon NIM_ADD 加上 Shell_NotifyIcon NIM_MODIFY.
        3.删除任务栏小图标Shell_NotifyIcon NIM_Delete操作.
        4.在添加任务栏图标的操作过程中,NOTIFYICONDATA结构中会指示响应的回调消息NOTIFYICONDATA,并绑定OnTrayNotification回调函数<供右键,双击动作处理>
     小点提及:Shell_NotifyIcon的封装才出来的***TaskBarIcon函数.实际上还是对Shell_NotifyIcon调用,OnSysCommand中的if(id)实际上是截获标题栏的最小化消息操作.

*/

总结:实际上就是Shell_NotifyIcon来进行任务栏图标添加与删除,再加上一个注册的结构<参数有消息>-利用消息与回调函数绑定机制.实现回调而已.

项目工程源码:http://download.csdn.net/detail/qq_24571549/9916444


  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值