考虑单窗口情况:

  假设自己通过new创建了一个窗口对象pWnd,然后pWnd->Create。则销毁窗口的调用次序:

  1. 手工调用pWnd->DestroyWindow();

  2. DestroyWindow会发送WM_DESTROY;

  3. WM_DESTROY对应的消息处理函数是OnDestroy();

  4. DestroyWindow会发送WM_NCDESTROY;

  5. WM_NCDESTROY对应的消息处理函数是OnNcDestroy;

  6. OnNcDestroy最后会调用PostNcDestroy;

  7. PostNcDestroy经常被用户重载以提供释放内存操作。例如可以使用delete this;

  通过这种方式,窗口对象对应的窗口和窗口对象本身都被释放了。

  如果含有子窗口:

  如果含有子窗口,则调用父窗口的DestroyWindow时,它会向子窗口发送WM_DESTROY和WM_NCDESTROY消息。

  具体调用顺序参考下文的例子。

  DestroyWindowdelete的影响:

  应该说前者对后者并没有什么影响。但经常在DestroyWindow间接导致执行的PostNcDestroy中delete窗口对象指针,即delete
this。

  CView::PostNcDestroy中唯一的操作就是delete
this;CframeWnd::PostNcDestory也是如此。而默认的CWnd::PostNcDestroy是空操作,CDialog中也没有对其进行重载,即也是空。

  deleteDestroy的影响:

  delete会导致析构函数。CWnd的析构函数中有对DestroyWindow的调用,但必须保证:

  m_hWnd != NULL &&

  this != (CWnd*) &wndTop
&&this !=
(CWnd*)&wndBottom
&&

  this != (CWnd*)&wndTopMost
&&this !=
(CWnd*)&wndNoTopMost。

  Cdialog的析构函数中也有对DestroyWindow的调用,但条件比较松,只需要m_hWnd !=
NULL。另外Cdialog::DoModal也会调用DestroyWindow。

  CFrameWnd的OnClose中会调用DestroyWindow,但其析构中不会调用DestroyWindow。

  CView的析构也不会调用DestroyWindow。

  一个SDI程序的销毁过程

  有CMainFrame类、CMyView类。并且CMyView有两个子窗口CMyDlg和CmyWnd的实例。

  点击退出按钮,CMainFrame会收到WM_CLOSE消息。CframeWnd(CMainFrame的父类)间接会调用
CWnd::DestroyWindow;它首先向CMyView发送WM_DESTORY和WM_NCDESTROY消息,并引发相应的处理函数;然后
向CMyDlg发送WM_DESTORY和WM_NCDESTROY消息,并引发相应的处理函数;然后向CMyWnd发送WM_DESTORY和
WM_NCDESTROY消息,并引发相应的处理函数。

  具体的执行顺序是:

  1. 调用CMainFrame::DestroyWindow

  2. CFrameWnd::OnDestroy

  3. CMyView::OnDestroy

  4. CmyWnd::OnDestroy

  5. CmyDlg::OnDestroy

  6. CmyWnd::PostNcDestroy

  7. CmyWnd的析构

  8. CmyDlg::OnDestroy

  9. CmyDlg的析构

  10. CMyView::PostNcDestroy

  11. CmyView的析构

  12. CMainFrame的析构

  13. CMainFrame::DestroyWindow退出

  上面情况是假设我们在CmyWnd和CmyDlg的PostNcDestroy中添加了delete
this。如果没有添加,则7,10不会执行。

  因为CView::PostNcDestroy中调用了delete
this,所以然后会执行CMyView的析构操作。因为CframeWnd::PostNcDestroy中调用了delete
this,所以最后执行CMainFrame的析构操作。

  如果自己的CmyDlg和CmyWnd在PostNcDestroy中有delete
this;则二者会被析构。否则内存泄漏。当然delete也可以放在CMyView的析构中做,只是不够OO。

  总结

  可以有两种方法销毁窗口对象对应的窗口和释放窗口对象指针。一种是通过DestroyWindow。这是比较好的方法,因为最后MFC会自动相应
WM_CLOSE导致CframWnd::DestroyWindow被调用,然后会一次释放所有子窗口的句柄。用户需要做的是在
PostNcDestroy中释放堆窗口对象指针。但因为某些对象是在栈中申请的,所以delete
this可能出错。这就要保证写程序时自己创建的窗口尽量使用堆申请。

  另一种是delete。Delete一个窗口对象指针有的窗口类(如CWnd,Cdialog)会间接调用DestroyWindow,有的窗口类(如CView,CframeWn)不会调用DestroyWindow。所以要小心应对。

  二者是相互调用的,很繁琐。

  一段很好的文章:(作者:闻怡洋)

  一个MFC窗口对象包括两方面的内容:一是窗口对象封装的窗口,即存放在m_hWnd成员中的HWND(窗口句柄),二是窗口对象本身是一个C++对象。要删除一个MFC窗口对象,应该先删除窗口对象封装的窗口,然后删除窗口对象本身。

  删除窗口最直接方法是调用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窗口对象具有自动清除的功能。

  如前面讲述非模态对话框时所提到的,当调用CWnd::DestroyWindow或::DestroyWindow删除一个窗口时,被删除窗口的
PostNcDestroy成员函数会被调用。缺省的PostNcDestroy什么也不干,但有些MFC窗口类会覆盖该函数并在新版本的
PostNcDestroy中调用delete
this来删除对象,从而具有了自动清除的功能。此类窗口对象通常是用new操作符创建在堆中的,但程序员不必操心用delete操作符去删除它们,因为
一旦调用DestroyWindow删除窗口,对应的窗口对象也会紧接着被删除。

  不具有自动清除功能的窗口类如下所示。这些窗口对象通常是以变量的形式创建的,无需自动清除功能。

  所有标准的Windows控件类。

  1. 从CWnd类直接派生出来的子窗口对象(如用户定制的控件)。

  2. 切分窗口类CSplitterWnd。

  3. 缺省的控制条类(包括工具条、状态条和对话条)。

  4. 模态对话框类。

  具有自动清除功能的窗口类如下所示,这些窗口对象通常是在堆中创建的。

  1. 主框架窗口类(直接或间接从CFrameWnd类派生)。

  2. 视图类(直接或间接从CView类派生)。

  读者在设计自己的派生窗口类时,可根据窗口对象的创建方法来决定是否将窗口类设计成可以自动清除的。例如,对于一个非模态对话框来说,其对象是创建在堆中的,因此应该具有自动清除功能。

  综上所述,对于MFC窗口类及其派生类来说,在程序中一般不必显式删除窗口对象。也就是说,既不必调用DestroyWindow来删除窗口对象封装
的窗口,也不必显式地用delete操作符来删除窗口对象本身。只要保证非自动清除的窗口对象是以变量的形式创建的,自动清除的窗口对象是在堆中创建
的,MFC的运行机制就可以保证窗口对象的彻底删除。

  如果需要手工删除窗口对象,则应该先调用相应的函数(如CWnd::DestroyWindow)删除窗口,然后再删除窗口对象.对于以变量形式创建
的窗口对象,窗口对象的删除是框架自动完成的.对于在堆中动态创建了的非自动清除的窗口对象,必须在窗口被删除后,显式地调用delete来删除对象(一
般在拥有者或父窗口的析构函数中进行).对于具有自动清除功能的窗口对象,只需调用CWnd::DestroyWindow即可删除窗口和窗口对象。注
意,对于在堆中创建的窗口对象,不要在窗口还未关闭的情况下就用delete操作符来删除窗口对象.

MFC DestroyWindow[转]的更多相关文章

  1. MFC DestroyWindow窗口对象和窗口句柄的销毁

    考虑单窗口情况: 假设自己通过new创建了一个窗口对象pWnd,然后pWnd->Create.则销毁窗口的调用次序: 1. 手工调用pWnd->DestroyWindow(): 2. De ...

  2. MFC对话框中使用CHtmlEditCtrl

    MFC对话框中使用CHtmlEditCtrl 感谢原帖作者: http://blog.csdn.net/tingya/article/details/2028172 我在VS2008校正了一些代码. ...

  3. MFC学习-第一课 MFC运行机制

    最近由于兴趣爱好,学习了孙鑫的MFC教程的第一课.看完视频了,自己便用visual studio 2010尝试了MFC编程,其中遇到了一些问题. 1.vs2010不像vs6.0那样可以新建一个空的MF ...

  4. MFC中对话框类(Dialog)的应用

    转载http://hi.baidu.com/jackywdx/item/feee8041d2c2e12310ee1e85 Windows应用程序通常是通过对话框接收用户输入.向用户输出信息,本节介绍应 ...

  5. C++ MFC实现基于RFID读写器的上位机软件

    C++ MFC实现基于RFID读写器的上位机软件 该博客涉及的完整工程托管在https://github.com/Wsine/UpperMonitor,觉得好请给个Star (/▽\=) 运行和测试环 ...

  6. Win32 DLL和MFC DLL 中封装对话框

    现在最常看见的关于DLL的问题就是如何在DLL中使用对话框,这是一个很普遍的关于如何在DLL中使用资源的问题.这里我们从Win32   DLL和MFC   DLL两个方面来分析并解决这个问题.     ...

  7. MFC浅析(7) CWnd类虚函数的调用时机、缺省实现

    CWnd类虚函数的调用时机.缺省实现 FMD(http://www.fmdstudio.net) 1. Create 2. PreCreateWindow 3. PreSubclassWindow 4 ...

  8. Cocos2d-X 2.2嵌入MFC的子窗口

    1.在cocos2dx目录下创建基于对话框的MFC工程,对话框中间放一个Picture控件 2.添加cocos2dx的相关头文件包含路径.库包含路径和依赖项,可以参考其他cocos工程设置 3.选中P ...

  9. MFC可编辑的ListCtrl

    近期由于项目的要求,需要一个可以编辑的列表控件,由于MFC提供的列表控件只支持第一行可编辑,无法满足项目需求,故只能自己动手重写一个列表控件.重写列表控件的思想为:当点击列表的某行某列时,在此处创建一 ...

随机推荐

  1. Windows Redis安装,Java操作Redis

    一.Redis 的安装 1.Redis 下载 Windows 版本下载:https://github.com/dmajkic/redis/downloads 2.解压到 C:\redis-2.4.5- ...

  2. 复制mysql数据库的步骤

    Navicat 转存sql文件 然后命令 mysql -uroot -p123456 dbname < e:/backup/20141014.sql

  3. 使用anaconda安装tensorflow (windows10环境)

    版权声明:勤学 修德 明辨 笃实 - CSDN周雄伟 https://blog.csdn.net/ebzxw/article/details/80701613 已有环境:python3.7.1 ana ...

  4. [Winform][C#]获取系统颜色预定义颜色和现有字体集

    转自: http://zhidao.baidu.com/link?url=ozY7tJRNBYHUsImE6jn1psqc8owib7MWcDMEmZw48q8iD9Hz9MWgnQQcBDO0VYO ...

  5. Map和Bean的相互转换

    Map和Bean的相互转换 BeanUtils位于org.apache.commons.beanutils.BeanUtils下面,其方法populate的作用解释如下: 完整方法: BeanUtil ...

  6. 0122(本来是想ak的但是因为智障只拿了200。)

    今天考了一场小测试,额,非常非常水,但是智障的我才A掉两道题. T1: 1.暑假作业   (mtime.pas/c/cpp) [问题描述] 暑假作业是必须要写的,越到假期结束前,写作业的效率就越高,小 ...

  7. hex文件和bin文件区别

    HEX文件和BIN文件是我们经常碰到的2种文件格式.因为自己也是新手,所以一直对这两个文件懵懵懂懂,不甚了解,最近在做STM32单片机的IAP更新,其中要考虑HEX文件和BIN文件,所以需要学习下这两 ...

  8. 解决Visual Studio Community 2017工具栏中没有Report Viewer的问题

    选择“工具”>“Nuget包管理器”>“程序包管理器控制台” 执行命令:Install-Package Microsoft.ReportingServices.ReportViewerCo ...

  9. MS SQL 流程控制语句

    Declare   myCursor   cursor   For     Select   *   from   table1         open   myCursor         Fet ...

  10. python模块的打包

    python模块的打包方法: http://blog.csdn.net/five3/article/details/7847551