Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Esta nota descreve a utilização do CWnd::PostNcDestroy método. Use esse método se quiser fazer a alocação personalizada de CWndobjetos derivados. Esta nota também explica por que você deve usar CWnd::DestroyWindow para destruir um objeto C++ do Windows em vez do delete operador.
Se você seguir as diretrizes deste artigo, terá poucos problemas de limpeza. Esses problemas podem resultar de problemas como esquecer de excluir/liberar memória C++, esquecer de liberar recursos do sistema como HWNDs ou liberar objetos muitas vezes.
O problema
Cada objeto de Windows (objeto de uma classe derivada de CWnd) representa tanto um objeto C++ quanto um HWND. Os objetos C++ são alocados no heap da aplicação e HWNDs são alocados nos recursos de sistema pelo gestor de janelas. Como há várias maneiras de destruir um objeto de janela, devemos fornecer um conjunto de regras que impeçam vazamentos de recursos ou memória do sistema. Essas regras também devem impedir que objetos e identificadores do Windows sejam destruídos mais de uma vez.
Destruindo janelas
A seguir estão as duas maneiras permitidas de destruir um objeto do Windows:
Chamando
CWnd::DestroyWindowou a APIDestroyWindowdo Windows.Exclusão explícita com o operador
delete.
O primeiro caso é, de longe, o mais comum. Este caso aplica-se mesmo que o seu código não chame DestroyWindow diretamente. Quando o usuário fecha diretamente uma janela de quadro, essa ação gera a mensagem WM_CLOSE e a resposta padrão a essa mensagem é chamar DestroyWindow. Quando uma janela pai é destruída, o Windows chama DestroyWindow para todas as janelas filhas.
O segundo caso, o uso do operador delete em objetos Windows, deve ser raro. A seguir estão alguns casos em que usar delete é a escolha correta.
Limpeza automática com CWnd::PostNcDestroy
Quando o sistema destrói uma janela do Windows, a última mensagem do Windows enviada para a janela é WM_NCDESTROY. O manipulador padrão CWnd para essa mensagem é CWnd::OnNcDestroy.
OnNcDestroy desanexará o HWND do objeto C++ e chamará a função PostNcDestroyvirtual. Algumas classes substituem essa função para excluir o objeto C++.
A implementação padrão de CWnd::PostNcDestroy não faz nada, o que é apropriado para objetos de janela alocados no quadro de pilha ou incorporados em outros objetos. Esse comportamento não é apropriado para objetos de janela projetados para alocação na heap sem quaisquer outros objetos. Em outras palavras, não é apropriado para objetos de janela que não estão incorporados em outros objetos C++.
As classes projetadas apenas para alocação no heap substituem o método PostNcDestroy para realizar uma delete this;. Esta instrução liberará qualquer memória associada ao objeto C++. Ainda que o destruidor padrão CWnd chame DestroyWindow se m_hWnd não for NULL, essa chamada não resulta em recursão infinita porque o identificador será desvinculado e NULL durante a fase de limpeza.
Observação
O sistema geralmente chama CWnd::PostNcDestroy depois de processar a mensagem do Windows WM_NCDESTROY e o HWND e o objeto de janela C++ não estão mais conectados. O sistema também chamará CWnd::PostNcDestroy na implementação da maioria das chamadas de CWnd::Create se ocorrer falha. As regras de limpeza automática são descritas mais adiante neste artigo.
Classes de limpeza automática
As classes a seguir não foram projetadas para limpeza automática. Tipicamente, eles são incorporados em outros objetos C++ ou na pilha:
Todos os controles padrão do Windows (
CStatic,CEdit,CListBox, e assim por diante).Qualquer janela filha derivada diretamente de
CWnd(por exemplo, controlos personalizados).Janelas divisórias (
CSplitterWnd).Barras de controlo padrão (classes derivadas de
CControlBar, consulte a Nota Técnica 31 para ativar a eliminação automática para objetos da barra de controlo).Caixas de diálogo (
CDialog) projetadas para diálogos modais na estrutura de pilha.Todas as caixas de diálogo padrão, exceto
CFindReplaceDialog.As caixas de diálogo padrão criadas por ClassWizard.
As classes a seguir são projetadas para limpeza automática. Eles normalmente são alocados sozinhos no heap.
Janelas de moldura principal (derivadas direta ou indiretamente de
CFrameWnd).Exibir janelas (derivadas direta ou indiretamente de
CView).
Se quiser quebrar estas regras, deve sobrescrever o método PostNcDestroy na sua classe derivada. Para adicionar a limpeza automática à sua classe, chame a classe base e faça um delete this;. Para remover a limpeza automática da sua classe, chame diretamente CWnd::PostNcDestroy em vez do método PostNcDestroy da sua classe base direta.
O uso mais comum de alterar o comportamento de limpeza automática é criar uma caixa de diálogo sem modo que pode ser alocada no heap.
Quando ligar delete
Recomendamos que você chame DestroyWindow para destruir um objeto do Windows, seja o método C++ ou a API global DestroyWindow .
Não chame a API global DestroyWindow para destruir uma janela MDI filha. Você deve usar o método CWnd::DestroyWindow virtual em vez disso.
Para objetos Window do C++ que não realizam limpeza automática, usar o operador delete pode causar um vazamento de memória quando tentar chamar DestroyWindow no destrutor CWnd::~CWnd se VTBL não apontar para a classe derivada correta. A fuga de memória ocorre porque o sistema não consegue encontrar o método adequado de eliminação a ser chamado. Usar DestroyWindow em vez de delete evitar esses problemas. Como esse erro pode ser sutil, compilar no modo de depuração gerará o seguinte aviso se você estiver em risco.
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
Para objetos C++ do Windows que executam limpeza automática, você deve chamar DestroyWindow. Se você usar o delete operador diretamente, o alocador de memória de diagnóstico MFC irá notificá-lo de que você está liberando memória duas vezes. As duas ocorrências são sua primeira chamada explícita e a chamada indireta para delete this; na implementação de limpeza automática do PostNcDestroy.
Depois de chamar DestroyWindow um objeto de limpeza não automática, o objeto C++ ainda estará por perto, mas m_hWnd será NULL. Depois de chamar DestroyWindow um objeto de limpeza automática, o objeto C++ desaparecerá, liberado pelo operador de exclusão C++ na implementação de limpeza automática do PostNcDestroy.