Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Nota:
La biblioteca Microsoft Foundation Classes (MFC) sigue siendo compatible. Sin embargo, ya no estamos agregando características ni actualizando la documentación.
En esta nota se describe el uso del CWnd::PostNcDestroy método . Use este método si desea realizar la asignación personalizada de objetos derivados de CWnd. En esta nota también se explica por qué debe usar CWnd::DestroyWindow para destruir un objeto de Windows de C++ en lugar del delete operador .
Si sigue las instrucciones de este artículo, tendrá pocos problemas de limpieza. Estos problemas pueden deberse a problemas como olvidar eliminar o liberar memoria de C++, olvidarse de liberar recursos del sistema como HWNDs o liberar objetos demasiadas veces.
El problema.
Cada objeto de Windows (objeto de una clase derivada de CWnd) representa un objeto de C++ y un HWND. Los objetos de C++ se asignan en el montón de la aplicación y el administrador de ventanas asigna HWND en los recursos del sistema. Dado que hay varias maneras de destruir un objeto de ventana, debemos proporcionar un conjunto de reglas que impidan pérdidas de memoria o recursos del sistema. Estas reglas también deben impedir que los objetos y identificadores de Windows se destruyan más de una vez.
Destrucción de ventanas
A continuación se muestran las dos maneras permitidas de destruir un objeto de Windows:
Llamar a
CWnd::DestroyWindowo a la API de WindowsDestroyWindow.Eliminar explícitamente con el operador
delete.
El primer caso es, en gran medida, el más común. Este caso se aplica incluso si el código no llama DestroyWindow directamente. Cuando el usuario cierra directamente una ventana de marco, esta acción genera el mensaje WM_CLOSE, y la respuesta predeterminada a este mensaje es llamar a DestroyWindow. Cuando se destruye una ventana primaria, Windows llama a DestroyWindow para todos sus elementos secundarios.
El segundo caso, el uso del delete operador en objetos de Windows debe ser poco frecuente. A continuación se muestran algunos casos en los que el uso delete es la opción correcta.
Limpieza automática con CWnd::PostNcDestroy
Cuando el sistema destruye una ventana de Windows, el último mensaje de Windows enviado a la ventana es WM_NCDESTROY. El controlador predeterminado CWnd de ese mensaje es CWnd::OnNcDestroy.
OnNcDestroy desasociará el HWND del objeto de C++ y llamará a la función virtual PostNcDestroy. Algunas clases invalidan esta función para eliminar el objeto de C++.
La implementación predeterminada de CWnd::PostNcDestroy no hace nada, lo cual es adecuada para los objetos de ventana asignados en el marco de pila o que están incrustados en otros objetos. Este comportamiento no es adecuado para los objetos de ventana diseñados para la asignación en el montón sin ningún otro objeto. En otras palabras, no es adecuado para los objetos de ventana que no están incrustados en otros objetos de C++.
Las clases diseñadas para la asignación por sí solas en el montón invalidan el método PostNcDestroy para realizar un delete this;. Esta instrucción liberará cualquier memoria asociada al objeto de C++. Aunque el destructor predeterminado CWnd llama a DestroyWindow si m_hWnd no es NULL, esta llamada no conduce a una recursividad infinita porque el identificador se desasociará y NULL durante la fase de limpieza.
Nota:
Normalmente, el sistema llama a CWnd::PostNcDestroy después de procesar el mensaje de Windows WM_NCDESTROY y HWND y el objeto de ventana de C++ ya no están conectados. El sistema también llamará a CWnd::PostNcDestroy en la implementación de la mayoría de las llamadas CWnd::Create si se produce un error. Las reglas de limpieza automática se describen más adelante en este artículo.
Clases de limpieza automática
Las siguientes clases no están diseñadas para la limpieza automática. Normalmente se insertan en otros objetos de C++ o en la pila:
Todos los controles estándar de Windows (
CStatic,CEdit,CListBox, etc.).Cualquier ventana secundaria derivada directamente de
CWnd(por ejemplo, controles personalizados).Ventanas divisoras (
CSplitterWnd).Barras de control predeterminadas (clases derivadas de
CControlBar, consulte la Nota técnica 31 para habilitar la eliminación automática para objetos de barra de control).Diálogos (
CDialog) diseñados para diálogos modales en el marco de pila.Todos los diálogos estándar excepto
CFindReplaceDialog.Los diálogos predeterminados creados por ClassWizard.
Las siguientes clases no están diseñadas para la limpieza automática. Normalmente se asignan por sí mismas en el montón:
Ventanas de marco principal (derivadas directa o indirectamente de
CFrameWnd).Ver ventanas (derivadas directas o indirectamente de
CView).
Si desea interrumpir estas reglas, debe invalidar el PostNcDestroy método en la clase derivada. Para agregar la limpieza automática a la clase, llame a la clase base y, a continuación, realice una delete this;. Para eliminar la limpieza automática de su clase, llame a CWnd::PostNcDestroy directamente en lugar de usar el método de la clase base directa PostNcDestroy.
El uso más común de cambiar el comportamiento de limpieza automática es crear un cuadro de diálogo de modelado que se pueda asignar en el montón.
Cuándo llamar delete
Se recomienda llamar DestroyWindow para destruir un objeto de Windows, ya sea utilizando el método de C++ o la API global DestroyWindow.
No llame a la API global DestroyWindow para destruir una ventana hija de MDI. En su lugar, debe usar el método CWnd::DestroyWindow virtual.
En el caso de los objetos Window de C++ que no realizan la limpieza automática, el uso del operador delete puede provocar una pérdida de memoria cuando intenta llamar a DestroyWindow en el destructor CWnd::~CWnd si VTBL no apunta a la clase derivada correctamente. La fuga se produce porque el sistema no encuentra el método de destrucción adecuado al que llamar. El uso DestroyWindow en lugar de delete evitar estos problemas. Dado que este error puede ser sutil, la compilación en modo de depuración generará la siguiente advertencia si está en riesgo.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
Para los objetos de Windows de C++ que realizan la limpieza automática, debe llamar a DestroyWindow. Si usa el delete operador directamente, el asignador de memoria de diagnóstico de MFC le notificará que está liberando memoria dos veces. Las dos repeticiones son la primera llamada explícita y la llamada indirecta a delete this; en la implementación de limpieza automática de PostNcDestroy.
Después de llamar a DestroyWindow en un objeto que no sea de limpieza automática, el objeto de C++ seguirá existiendo, pero m_hWnd será NULL. Después de llamar a DestroyWindow en un objeto de limpieza automática, el objeto de C++ desaparecerá, liberado por el operador delete de C++ en la implementación de limpieza automática de PostNcDestroy.