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 CWnd
dé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 HWND
des 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 HWND
sont 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 APIDestroyWindow
Windows .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 PostNcDestroy
virtuelle . 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
,CListBox
etc.).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
CFindReplaceDialog
de .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
.