Você está na página 1de 2

Destroying Window Objects

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

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

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

This is important. If you follow the guidelines below, you will have few cleanup problems (such as
forgetting to delete/free C++ memory, forgetting to free system resources like HWNDs, or freeing objects
too many times).

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 default WM_CLOSE
behavior is to call DestroyWindow), and when a parent window is destroyed, Windows calls
DestroyWindow 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 is WM_NCDESTROY.
The default CWnd handler for that message (CWnd::OnNcDestroy) will detach the HWND from the C+
+ object and call the virtual function PostNcDestroy. 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 the PostNcDestroy
member function to perform a "delete this". This statement will free any C++ memory associated with
the C++ object. Even though the default CWnd destructor calls DestroyWindow if m_hWnd is non-
NULL, this does not lead to infinite recursion since the handle will be detached and NULL during the
cleanup phase.

Note

CWnd::PostNcDestroy is normally called after the Windows WM_NCDESTROY message is


processed, as part of window destruction, and the HWND and the C++ window object are no
longer attached. CWnd::PostNcDestroy will also be called in the implementation of most
Create calls if failure occurs (see below for auto cleanup rules).
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 a delete this. To
remove auto-cleanup from your class, call CWnd::PostNcDestroy directly instead of the PostNcDestroy
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
function CWnd::DestroyWindow instead.

For C++ Window objects that do not perform auto-cleanup, using DestroyWindow instead of delete
avoids problems of having to call DestroyWindow in the CWnd::~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

Copy Code
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 call DestroyWindow. If
you use operator delete directly, the MFC diagnostic memory allocator will alert you that you are freeing
memory twice (the first call to delete as well as the indirect call to "delete this" in the auto-cleanup
implementation of PostNcDestroy).

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

Você também pode gostar