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

考虑单窗口情况:

  假设自己通过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消息。

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

  DestroyWindow对delete的影响:

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

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

  delete对Destroy的影响:

  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操作符来删除窗口对象.

本文来自:http://blog.sina.com.cn/s/blog_557d25460100gz0e.html

时间: 2024-10-21 15:30:20

MFC DestroyWindow窗口对象和窗口句柄的销毁的相关文章

MFC永久窗口对象与临时窗口对象

这篇讲得很清楚,就转过来了,原文如下: 因项目需要,最近在学习MFC,下午在一篇教程中提到了临时窗口.永久窗口,作者让读者自行查阅MSDN,了解临时窗口与永久窗口的概念,出于好奇,出于方便,直接百度一下,看到了几篇题为解释临时窗口与永久窗口的文章,随后网友在论坛中附上了MSDN中的原文,仔细翻译一下,发现网上查到的几篇文章,对这个概念的解释是有问题和不足的. 首先我要说明一点的就是窗口是没有临时与永久之分的,窗口是一种资源,随着CreateWindow的调用而产生,随着DestroyWindow

MFC子窗口和父窗口(SetParent,SetOwner)

一.概念和区别 在windows系统中,每个窗口对象都对应有一个数据结构,形成一个list链表.系统的窗口管理器通过这个list来获取窗口信息和管理每个窗口.这个数据结构中有四个数据用来构建list,即child.sibling.parent.owner四个域.所以我们可以看到,窗口之间的关系有两种:owner-owned 关系和 parent-child关系.前者称之为拥有/被拥有关系,后者称之为父/子关系.在这篇文字中,我把owner窗口称之所有者窗口.换句话说,一个窗口在有一个父窗口(pa

c++-小弟请教在MFC中子窗口如何获取父窗口的句柄啊

问题描述 小弟请教在MFC中子窗口如何获取父窗口的句柄啊 比如我有个父类的Dialog类为A,还有一个子类的Dialog类为B,然后在A类的头文件中包含了B的头文件,然后在A类中生命一个B类的成员变量,类似下面那样,然后我通过一个button调用DoModal();B类的STYLE改为CHILD了: 然后我希望在子窗口中处理一些数据,然后传给父窗口:比如A中有个IDC_text1 有个IDD_BUTTON1,B中有个IDC_text2,有个IDD_BUTTON2: 我就希望在B中的IDC_tex

mfc 窗口通信-mfc 对话框窗口分割后通信通信

问题描述 mfc 对话框窗口分割后通信通信 将对话框分割为两个窗口,如何实现这连个窗口之间的通信新手,求指导谢谢 解决方案 对话框分割后还是一个窗口,而不是两个.所以只要定义成员变量,就可以互相传值 解决方案二: 获取窗口句柄,然后发消息用postmessage 收消息用getmessage或peekmessage 解决方案三: 都通过对话框本身的实例对象来通信,它可以访问两个窗口 解决方案四: 要看你这个分隔是怎么分隔了.1. 中间划了一条竖线,额,这个嘛,互相可以访问了2. 的的确确分了两个

MFC父窗口控制子窗口CListCtrl控件刷新的问题

问题描述 MFC父窗口控制子窗口CListCtrl控件刷新的问题 目标:父窗口单击按钮,向子窗口发送一个消息:子窗口的消息处理函数中,调用列表显示函数来刷新列表数据. 我的代码: // 父窗口void CDlg4::OnButtonClick(){ CDlg43 *dlg = new CDlg43(); dlg->Create(IDD_DIALOG_43this); if (NULL == dlg) { AfxMessageBox(""failed""); d

在MFC主窗口添加按钮和消息响应

问题描述 在MFC主窗口添加按钮和消息响应 我希望能在mfc主窗口上添加按钮和其详细响应,按钮载入icon位图,注意不是在对话框和工具栏上,希望能给出详细的例子 解决方案 不知道你的主窗口是什么,如果是sdi/mdi应用程序,最简单的是用向导创建程序,最后一部,让你的view从CFormView继承. 这样会产生一个对话框资源,你直接往里面摆控件,就可以加载在界面上了. 至于按钮插入位图,可以通过重绘实现. 解决方案二: mfc主窗口指的是窗体上还是主客户区,后者直接按照一楼的做也是可以的,要是

窗口通信-【MFC分割窗口后的单文档怎么变为多文档??】

问题描述 [MFC分割窗口后的单文档怎么变为多文档??] 网上的办法使过,好像不行:原因可能就是因为窗口被分割了的原因,我将分割窗口的过程全部屏蔽掉以后从单文档变为多文档没有问题.如果加上窗口分割以后就不能变为多文档了.下面是单文档和多文档的差别之一,我的问题也就是在这里.[其实我问题的原因是这样的,想在菜单中弄一个新建文档的命令,而多文档刚好可以解决这个问题,如果能解决这个问题也照样给分] 解决方案 //多文档CMultiDocTemplate* pDocTemplate;pDocTempla

view窗口透明作图-MFC view窗口透明设置

问题描述 MFC view窗口透明设置 基于MFC单文档程序,设置2个工具按钮,一个使画图背景为默认模式,另一个使view窗口透明直接在桌面作图...默认启动时只显示工具栏 我的做法是开始设置 view Precreatewindow cs cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW);// view背景透明 只显示工具栏.这个功能Ok. onbutton1: 加载一个类似默认背景白色的图片..这个功能也ok. Onbutton

对话框-求一个MFC记事本窗口的记忆功能的实现?

问题描述 求一个MFC记事本窗口的记忆功能的实现? 如果窗口关闭的时候状态是最大化的,那么下次打开还是最大化的,如果不是最大化的,打开就不是最大化的.为什么SDI窗口就有,而对话框就没有呢? 解决方案 GetWindowPlacement得到窗口状态,存入注册表http://baike.baidu.com/link?url=ypOTXE4bQdo_rccie2nDnF9qg5i3zN_LlUkZ-g91YHln7S3K8ERtA2XLJeLuf2f2Yia-NpywABvx75a7zsqiLa