【销毁窗口】TN017: Destroying Window Objects

摘自:MSDN Library for Visual Studio 2005


This note describes the use of the CWnd::PostNcDestroy member function. Use this function if you wish to do customized allocation ofCWnd-derived objects.

This note also explains some of the reasons for the cardinal rule:

To destroy a C++ Windows object, use DestroyWindow, not "delete".


The Problem

Windows objects (objects of classes derived from CWnd) represent both a C++ object (allocated in the application's heap) and an HWND (allocated in system resources by the window manager). Since there are several ways to destroy a window object, we must provide a set of rules that prevent system resource or application memory leaks and that prevent objects and Windows handles from being destroyed more than once.

This is more than a memory management problem. The presence of a Windows window has user-interface impact: a window drawn on the screen; once it is destroyed, there is also an impact on system resources. Leaking C++ memory in your application address space is not as bad as leaking system resources.


Destroying Windows

The two permitted ways to destroy a Windows object are:

  • Calling CWnd::DestroyWindow or the Windows API ::DestroyWindow.

  • Explicitly deleting with the delete operator.

The first case is by far the most common. This case applies even if DestroyWindow is not called directly by your code. This is the case when the user directly closes a frame window (the defaultWM_CLOSE behavior is to callDestroyWindow), and when a parent window is destroyed, Windows callsDestroyWindow for all the children.

The second case, the use of the delete operator on Windows objects, should be very rare and only in the cases outlined below.


Auto Cleanup with CWnd::PostNcDestroy

When destroying a Windows window, the last Windows message sent to the window isWM_NCDESTROY. The defaultCWnd handler for that message (CWnd::OnNcDestroy) will detach theHWND from the C++ object and call the virtual functionPostNcDestroy. Some classes override this function to delete the C++ object.

The default implementation of CWnd::PostNcDestroy does nothing which is appropriate for window objects allocated on the stack frame or embedded in other objects. This is not appropriate for window objects that are designed to be allocated by themselves on the heap (not embedded in other C++ object).

Those classes that are designed to be allocated by themselves on the heap override thePostNcDestroy member function to perform a "delete this". This statement will free any C++ memory associated with the C++ object. Even though the defaultCWnd destructor calls DestroyWindow ifm_hWnd is non-NULL, this does not lead to infinite recursion since the handle will be detached and NULL during the cleanup phase.


Auto Cleanup Classes

The following classes are not designed for auto-cleanup. They are normally embedded in other C++ object or on the stack:

  • All standard Windows controls (CStatic, CEdit,CListBox, and so on).

  • Any child windows derived directly from CWnd (for example, custom controls).

  • Splitter windows (CSplitterWnd).

  • Default control bars (classes derived from CControlBar, see Technical Note 31 for enabling auto-delete for control bar objects).

  • Dialogs (CDialog) designed for modal dialogs on the stack frame.

  • All the standard dialogs except CFindReplaceDialog.

  • The default dialogs created by ClassWizard.

The following classes are designed for auto-cleanup. They are normally allocated by themselves on the heap:

  • Main frame windows (derived directly or indirectly from CFrameWnd).

  • View windows (derived directly or indirectly from CView).

If you wish to break any of these rules, you must override the PostNcDestroy member function in your derived class. To add auto-cleanup to your class, call your base class and then do adelete this. To remove auto-cleanup from your class, call CWnd::PostNcDestroy directly instead of thePostNcDestroy member in your direct base class.

The most common use of the above is to create a modeless dialog that can be allocated on the heap.


When to Call 'delete'

The recommended way to destroy a Windows object is to call DestroyWindow, either the C++ member function or the global::DestroyWindow API.

Do not call the global ::DestroyWindow API to destroy an MDI Child window; use the virtual member functionCWnd::DestroyWindow instead.

For C++ Window objects that do not perform auto-cleanup, using DestroyWindow instead ofdelete avoids problems of having to callDestroyWindow in theCWnd::~CWnd destructor where the VTBL is not pointing to the correctly derived class. This can lead to subtle bugs so the diagnostic (debug) version of MFC will warn you with

  
Warning: calling DestroyWindow in CWnd::~CWnd
   OnDestroy or PostNcDestroy in derived class will not be called

In the case of C++ Windows objects that do perform auto-cleanup, you must callDestroyWindow. If you use operatordelete directly, the MFC diagnostic memory allocator will alert you that you are freeing memory twice (the first call todelete as well as the indirect call to "delete this" in the auto-cleanup implementation ofPostNcDestroy).

After calling DestroyWindow on a non-auto-cleanup object, the C++ object will still be around, butm_hWnd will be NULL. After callingDestroyWindow on an auto-cleanup object, the C++ object will be gone, freed by the C++ delete operator in the auto-cleanup implementation ofPostNcDestroy.


总结:

1,销毁窗口的最佳做法是使用DestroyWindow

2,重载CWnd::PostNcDestroy可以修改窗口类的“自销毁”行为

3,对于具有自销毁能力的窗口类,调用DestroyWindow后,C++对象不再存在

4,对于不具有自销毁能力的窗口类,调用DestroyWindow后,C++对象仍存在




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值