Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Observação
A biblioteca Microsoft Foundation Classes (MFC) continua sendo suportada. No entanto, não estamos mais adicionando recursos ou atualizando a documentação.
Esta observação descreve o uso do CWnd::PostNcDestroy método. Use esse método se quiser fazer a alocação personalizada de objetos derivados de CWnd. Esta observação 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 neste 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 windows (objeto de uma classe derivada CWnd) representa um objeto C++ e um HWND. Os objetos C++ são alocados no heap do aplicativo e HWNDs são alocados em recursos do sistema pelo gerenciador 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
Veja a seguir as duas maneiras permitidas de destruir um objeto do Windows:
Chamar
CWnd::DestroyWindowou a API do WindowsDestroyWindow.Excluir explicitamente com o operador
delete.
O primeiro caso é de longe o mais comum. Esse caso se aplica mesmo que seu código não chame DestroyWindow diretamente. Quando o usuário fecha diretamente uma janela de quadros, essa ação gera a mensagem WM_CLOSE e a resposta padrão para essa mensagem é chamar DestroyWindow. Quando uma janela pai é destruída, o Windows chama DestroyWindow para todos os filhos dela.
O segundo caso, o uso do delete operador em objetos windows, deve ser raro. Veja a seguir 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 dessa mensagem é CWnd::OnNcDestroy.
OnNcDestroy desanexará o HWND do objeto C++ e chamará a função virtual PostNcDestroy. 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 registro de ativação ou inseridos em outros objetos. Esse comportamento não é apropriado para objetos de janela projetados para alocação no heap sem outros objetos. Em outras palavras, não é apropriado para objetos de janela que não estão inseridos em outros objetos C++.
Classes projetadas apenas para alocação no heap substituem o método PostNcDestroy para executar um delete this;. Essa instrução liberará qualquer memória associada ao objeto C++. Embora o destruidor padrão CWnd chame DestroyWindow se m_hWnd não for NULL, essa chamada não levará à recursão infinita porque o identificador será desanexado e NULL durante a fase de limpeza.
Observação
O sistema geralmente chama CWnd::PostNcDestroy depois que processa a mensagem WM_NCDESTROY do Windows, e o HWND e o objeto C++ do Windows não estão mais conectados. O sistema também chamará CWnd::PostNcDestroy na implementação da maioria das chamadas CWnd::Create se ocorrer falha. As regras de limpeza automática são descritas posteriormente neste artigo.
Classes de limpeza automática
As classes a seguir não são projetadas para limpeza automática. Normalmente, elas são inseridas em outros objetos C++ ou na pilha:
Todos os controles padrão do Windows (
CStaticeCEditCListBoxassim por diante).Qualquer janela filha derivada diretamente de
CWnd(por exemplo, controles personalizados).Janelas divisoras (
CSplitterWnd).Barras de controle padrão (classes derivadas de
CControlBar, consulte a Observação Técnica 31 para habilitar a exclusão automática para objetos da barra de controle).Caixas de diálogo (
CDialog) projetadas para caixas de diálogo modais no registro de ativação.Todas as caixas de diálogo padrão, exceto
CFindReplaceDialog.As caixas de diálogo padrão criadas pelo ClassWizard.
As classes a seguir são projetadas para limpeza automática. Eles normalmente são alocados por si mesmos no heap:
Janelas de quadro principal (derivadas direta ou indiretamente de
CFrameWnd).Exibir janelas (derivadas direta ou indiretamente de
CView).
Se você quiser quebrar essas regras, deverá sobrescrever o método PostNcDestroy em sua classe derivada. Para adicionar a funcionalidade de limpeza automática à sua classe, chame a classe base e em seguida execute um delete this;. Para remover a limpeza automática de sua classe, chame CWnd::PostNcDestroy diretamente em vez do PostNcDestroy método de sua classe base direta.
O uso mais comum da alteração do comportamento de limpeza automática é criar uma caixa de diálogo sem janela restrita que possa ser alocada no heap.
Quando chamar delete
Recomendamos que você chame DestroyWindow para destruir um objeto Windows, seja o método C++ ou a API global DestroyWindow.
Não chame a API global DestroyWindow para destruir uma janela MDI Child. Em vez disso, você deve usar o método CWnd::DestroyWindow virtual.
Para objetos de janela C++ que não executam a limpeza automática, o uso do operador delete pode causar um vazamento de memória ao tentar chamar DestroyWindow no destruidor CWnd::~CWnd se VTBL não apontar para a classe derivada correta. O vazamento ocorre porque o sistema não pode encontrar o método de destruição apropriado para chamar. Usar DestroyWindow em vez de delete evitar esses problemas. Como esse erro pode ser sutil, a compilação no modo de depuração gerará o aviso a seguir 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 a limpeza automática, você deve chamar DestroyWindow. Se você usar o delete operador diretamente, o alocador de memória de diagnóstico MFC notificará você de que você está liberando memória duas vezes. As duas ocorrências são a sua primeira chamada explícita e a chamada indireta para delete this; na implementação de limpeza automática de PostNcDestroy.
Depois de chamar DestroyWindow em um objeto sem limpeza automática, o objeto C++ ainda estará presente, mas m_hWnd será NULL. Depois de chamar DestroyWindow em um objeto de auto-limpeza, o objeto C++ desaparecerá, liberado pelo operador delete da implementação de auto-limpeza de PostNcDestroy.