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.
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á algunos 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 HWNDlos asigna en los recursos del sistema mediante el administrador de ventanas. 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 APIDestroyWindowde Windows .Eliminar explícitamente con el
deleteoperador .
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 DestroyWindowa . Cuando se destruye una ventana primaria, Windows llama DestroyWindow a 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á del HWND objeto de C++ y llamará a la función PostNcDestroyvirtual . Algunas clases invalidan esta función para eliminar el objeto de C++.
La implementación predeterminada de no hace nada, que es adecuado para los objetos de ventana asignados en el marco de CWnd::PostNcDestroy pila o 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 PostNcDestroy método para realizar un delete this;. Esta instrucción liberará cualquier memoria asociada al objeto de C++. Aunque el destructor predeterminado CWnd llama DestroyWindow a si m_hWnd no NULLes , 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 CWnd::PostNcDestroy a después de procesar el mensaje de Windows WM_NCDESTROY y HWND el objeto de ventana de C++ ya no están conectados. El sistema también llamará CWnd::PostNcDestroy a en la implementación de la mayoría CWnd::Create de las llamadas 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 están diseñadas para la limpieza automática. Normalmente se asignan por sí mismos en el montón:
Ventanas de marco principal (derivadas directas 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;acción . Para quitar la limpieza automática de la clase, llame CWnd::PostNcDestroy directamente en lugar del método de la PostNcDestroy clase base directa.
El uso más común de cambiar el comportamiento de limpieza automática es crear un cuadro de diálogo modeless que se puede asignar en el montón.
Cuándo llamar delete
Se recomienda llamar DestroyWindow a para destruir un objeto de Windows, ya sea el método de C++ o la API global DestroyWindow .
No llame a la API global DestroyWindow para destruir una ventana secundaria 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 delete operador puede provocar una pérdida de memoria al intentar llamar DestroyWindow al CWnd::~CWnd destructor si no VTBL 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++ quedará liberado por el operador delete de C++ en la implementación de limpieza automática de PostNcDestroy.