Share via


TN017 : Destruction d’objets fenêtres

Cette note décrit l’utilisation de la CWnd::PostNcDestroy méthode. Utilisez cette méthode si vous souhaitez effectuer une allocation personnalisée d’objets CWnddérivés. Cette note explique également pourquoi vous devez utiliser CWnd::DestroyWindow pour détruire un objet Windows C++ au lieu de l’opérateur delete .

Si vous suivez les instructions de cet article, vous aurez peu de problèmes de propre up. Ces problèmes peuvent résulter de problèmes tels que l’oubli de supprimer/libérer de la mémoire C++, d’oublier de libérer des ressources système telles que HWNDdes s ou libérer des objets trop souvent.

La problématique

Chaque objet Windows (objet d’une classe dérivée de CWnd) représente à la fois un objet C++ et un HWND. Les objets C++ sont alloués dans le tas de l’application et HWNDsont alloués dans les ressources système par le gestionnaire de fenêtres. Étant donné qu’il existe plusieurs façons de détruire un objet fenêtre, nous devons fournir un ensemble de règles qui empêchent les fuites de ressources système ou de mémoire. Ces règles doivent également empêcher les objets et les handles Windows d’être détruits plusieurs fois.

Destruction de fenêtres

Voici les deux façons autorisées de détruire un objet Windows :

  • Appel CWnd::DestroyWindow ou API DestroyWindowWindows .

  • Suppression explicite avec l’opérateur delete .

Le premier cas est loin le plus courant. Ce cas s’applique même si votre code n’appelle DestroyWindow pas directement. Lorsque l’utilisateur ferme directement une fenêtre frame, cette action génère le message WM_CLOSE et la réponse par défaut à ce message consiste à appeler DestroyWindow. Lorsqu’une fenêtre parente est détruite, Windows appelle DestroyWindow tous ses enfants.

Le deuxième cas, l’utilisation de l’opérateur delete sur les objets Windows doit être rare. Voici quelques cas où l’utilisation delete est le bon choix.

Propre up automatique avecCWnd::PostNcDestroy

Lorsque le système détruit une fenêtre Windows, le dernier message Windows envoyé à la fenêtre est WM_NCDESTROY. Le gestionnaire par défaut CWnd de ce message est CWnd::OnNcDestroy. OnNcDestroy détache l’objet HWND C++ et appelle la fonction PostNcDestroyvirtuelle . Certaines classes remplacent cette fonction pour supprimer l’objet C++.

L’implémentation par défaut ne CWnd::PostNcDestroy fait rien, ce qui convient aux objets de fenêtre alloués sur le cadre de pile ou incorporés dans d’autres objets. Ce comportement n’est pas approprié pour les objets de fenêtre conçus pour l’allocation sur le tas sans aucun autre objet. En d’autres termes, il n’est pas approprié pour les objets de fenêtre qui ne sont pas incorporés dans d’autres objets C++.

Les classes conçues pour l’allocation seule sur le tas remplacent la PostNcDestroy méthode pour effectuer un delete this;. Cette instruction libère toute mémoire associée à l’objet C++. Même si le destructeur par défaut CWnd appelle DestroyWindow si m_hWnd ce n’est pas le casNULL, cet appel n’entraîne pas de récursivité infinie, car le handle sera détaché et NULL pendant la phase de propre up.

Remarque

Le système appelle CWnd::PostNcDestroy généralement après qu’il traite le message Windows WM_NCDESTROY et l’objet HWND fenêtre C++ ne sont plus connectés. Le système appelle CWnd::PostNcDestroy également dans l’implémentation de la plupart CWnd::Create des appels en cas de défaillance. Les règles de propre up automatique sont décrites plus loin dans cet article.

Classes de propre automatique

Les classes suivantes ne sont pas conçues pour la propre up automatique. Ils sont généralement incorporés dans d’autres objets C++ ou sur la pile :

  • Tous les contrôles Windows standard (CStatic, CEdit, CListBoxetc.).

  • Toutes les fenêtres enfants dérivées directement de CWnd (par exemple, des contrôles personnalisés).

  • Fenêtres fractionnées (CSplitterWnd).

  • Barres de contrôle par défaut (classes dérivées de CControlBar, consultez la note technique 31 pour activer la suppression automatique pour les objets de barre de contrôle).

  • Boîtes de dialogue (CDialog) conçues pour les dialogues modals sur le cadre de la pile.

  • Tous les dialogues standard à l’exception CFindReplaceDialogde .

  • Boîtes de dialogue par défaut créées par ClassWizard.

Les classes suivantes sont conçues pour la propre up automatique. Ils sont généralement alloués par eux-mêmes sur le tas :

  • Fenêtres de trame principale (dérivées directement ou indirectement de CFrameWnd).

  • Afficher les fenêtres (dérivées directement ou indirectement de CView).

Si vous souhaitez interrompre ces règles, vous devez remplacer la PostNcDestroy méthode dans votre classe dérivée. Pour ajouter automatiquement propre up à votre classe, appelez votre classe de base, puis effectuez un delete this;. Pour supprimer la propre up automatique de votre classe, appelez CWnd::PostNcDestroy directement au lieu de la PostNcDestroy méthode de votre classe de base directe.

L’utilisation la plus courante de la modification du comportement de propre up automatique consiste à créer une boîte de dialogue sans mode qui peut être allouée sur le tas.

Quand appeler delete

Nous vous recommandons d’appeler DestroyWindow pour détruire un objet Windows, soit la méthode C++ soit l’API globale DestroyWindow .

N’appelez pas l’API globale DestroyWindow pour détruire une fenêtre enfant MDI. Vous devez utiliser la méthode CWnd::DestroyWindow virtuelle à la place.

Pour les objets Window C++ qui n’effectuent pas de propre up automatiquement, l’utilisation de l’opérateur delete peut provoquer une fuite de mémoire lorsque vous essayez d’appeler DestroyWindow dans le CWnd::~CWnd destructeur si la VTBL classe dérivée correctement ne pointe pas vers la classe dérivée. La fuite se produit parce que le système ne trouve pas la méthode de destruction appropriée à appeler. L’utilisation DestroyWindow au lieu d’éviter delete ces problèmes. Étant donné que cette erreur peut être subtile, la compilation en mode débogage génère l’avertissement suivant si vous êtes à risque.

Warning: calling DestroyWindow in CWnd::~CWnd
    OnDestroy or PostNcDestroy in derived class will not be called

Pour les objets Windows C++ qui effectuent une propre up automatique, vous devez appeler DestroyWindow. Si vous utilisez l’opérateur delete directement, l’allocateur de mémoire de diagnostic MFC vous informe que vous libérez la mémoire deux fois. Les deux occurrences sont votre premier appel explicite et l’appel indirect à delete this; dans l’implémentation de propre up automatique de PostNcDestroy.

Une fois que vous avez appelé DestroyWindow un objet non-propre up, l’objet C++ sera toujours autour, mais m_hWnd sera NULL. Une fois que vous avez appelé DestroyWindow un objet de propre up automatiquement, l’objet C++ est supprimé, libéré par l’opérateur de suppression C++ dans l’implémentation de propre up automatique de PostNcDestroy.

Voir aussi

Notes techniques par numéro
Notes techniques par catégorie