TN017: Zerstören von Fensterobjekten

In diesem Hinweis wird die Verwendung der CWnd::PostNcDestroy Methode beschrieben. Verwenden Sie diese Methode, wenn Sie eine angepasste Zuordnung von CWndabgeleiteten Objekten ausführen möchten. In diesem Hinweis wird auch erläutert, warum Sie anstelle des delete Operators ein C++-Windows-Objekt zerstören solltenCWnd::DestroyWindow.

Wenn Sie die Richtlinien in diesem Artikel befolgen, gibt es nur wenige sauber Up-Probleme. Diese Probleme können zu Problemen führen, z. B. das Löschen/Freigeben des C++-Speichers, das Vergessen, Systemressourcen wie HWNDs freizugeben oder Objekte zu oft freizugeben.

Das Problem

Jedes Fensterobjekt (Objekt einer von ) abgeleiteten CWndKlasse stellt sowohl ein C++-Objekt als auch ein HWND. C++-Objekte werden im Heap der Anwendung zugeordnet und HWNDwerden vom Fenster-Manager in Systemressourcen zugewiesen. Da es mehrere Möglichkeiten gibt, ein Fensterobjekt zu zerstören, müssen wir eine Reihe von Regeln bereitstellen, die Systemressourcen oder Speicherverluste verhindern. Diese Regeln müssen auch verhindern, dass Objekte und Windows-Handles mehr als einmal zerstört werden.

Zerstörte Fenster

Im Folgenden sind die beiden zulässigen Methoden zum Zerstören eines Windows-Objekts aufgeführt:

  • Aufrufen CWnd::DestroyWindow oder die Windows-API DestroyWindow.

  • Explizites Löschen mit dem delete Operator.

Der erste Fall ist bei weitem am häufigsten. Dieser Fall gilt auch dann, wenn Ihr Code nicht direkt aufruft DestroyWindow . Wenn der Benutzer ein Framefenster direkt schließt, generiert diese Aktion die WM_CLOSE Nachricht, und die Standardantwort auf diese Nachricht besteht darin, aufzurufen DestroyWindow. Wenn ein übergeordnetes Fenster zerstört wird, ruft Windows alle untergeordneten Elemente auf DestroyWindow .

Der zweite Fall, die Verwendung des delete Operators für Windows-Objekte, sollte selten sein. Im Folgenden sind einige Fälle aufgeführt, in denen die Verwendung delete die richtige Wahl ist.

Automatisches sauber up mitCWnd::PostNcDestroy

Wenn das System ein Windows-Fenster zerstört, wird WM_NCDESTROYdie letzte windows-Nachricht, die an das Fenster gesendet wurde, angezeigt. Der Standardhandler CWnd für diese Nachricht lautet CWnd::OnNcDestroy. OnNcDestroy wird das HWND vom C++-Objekt getrennt und die virtuelle Funktion PostNcDestroyaufgerufen. Einige Klassen überschreiben diese Funktion, um das C++-Objekt zu löschen.

Die Standardimplementierung von CWnd::PostNcDestroy "does nothing", die für Fensterobjekte geeignet ist, die im Stapelframe zugeordnet sind oder in andere Objekte eingebettet sind. Dieses Verhalten eignet sich nicht für Fensterobjekte, die für die Zuordnung auf dem Heap ohne andere Objekte vorgesehen sind. Das heißt, es ist nicht für Fensterobjekte geeignet, die nicht in andere C++-Objekte eingebettet sind.

Klassen, die für die Zuordnung allein für den Heap vorgesehen sind, setzen die PostNcDestroy Methode außer Kraft, um eine delete this;. Diese Anweisung gibt alle Arbeitsspeicher frei, die dem C++-Objekt zugeordnet sind. Obwohl die Standarddestruktoraufrufe DestroyWindow CWnd andernfalls m_hWnd nicht NULLerfolgen, führt dieser Aufruf nicht zu unendlicher Rekursion, da der Handle getrennt und NULL während der sauber upphase getrennt wird.

Hinweis

Das System wird in der Regel aufgerufen CWnd::PostNcDestroy , nachdem die Windows-Nachricht WM_NCDESTROY verarbeitet wurde, und das HWND C++-Fensterobjekt ist nicht mehr verbunden. Das System ruft CWnd::PostNcDestroy auch die Implementierung der meisten CWnd::Create Aufrufe auf, wenn ein Fehler auftritt. Die Regeln für die automatische sauber up werden weiter unten in diesem Artikel beschrieben.

Auto-sauber up-Klassen

Die folgenden Klassen sind nicht für die automatische sauber up ausgelegt. Sie sind in der Regel in andere C++-Objekte oder auf dem Stapel eingebettet:

  • Alle standardmäßigen Windows-Steuerelemente (CStatic, CEdit, CListBoxusw.).

  • Alle untergeordneten Fenster, die direkt von CWnd (z. B. benutzerdefinierten Steuerelementen) abgeleitet werden.

  • Splitterfenster (CSplitterWnd).

  • Standardsteuerungsleisten (klassen abgeleitet, CControlBarsiehe Technisches Hinweis 31 zum Aktivieren der automatischen Löschung für Steuerelementleistenobjekte).

  • Dialoge (CDialog) entwickelt für modale Dialogfelder im Stapelframe.

  • Alle Standarddialogfeld mit Ausnahme CFindReplaceDialogvon .

  • Die standarddialogischen Dialogfelder, die von ClassWizard erstellt wurden.

Die folgenden Klassen sind für die automatische sauber up konzipiert. Sie werden in der Regel selbst auf dem Heap zugeordnet:

  • Hauptrahmenfenster (direkt oder indirekt von CFrameWnd).

  • Ansichtsfenster (direkt oder indirekt von CView).

Wenn Sie diese Regeln unterbrechen möchten, müssen Sie die PostNcDestroy Methode in der abgeleiteten Klasse überschreiben. Wenn Sie Ihrem Kurs automatisch sauber up hinzufügen möchten, rufen Sie Ihre Basisklasse auf, und führen Sie dann eine delete this;. Wenn Sie die automatische sauber aus Ihrer Klasse entfernen möchten, rufen Sie CWnd::PostNcDestroy direkt anstelle der PostNcDestroy Methode Der direkten Basisklasse auf.

Die am häufigsten verwendete Verwendung des Verhaltens der automatischen sauber up besteht darin, ein modusloses Dialogfeld zu erstellen, das für den Heap zugewiesen werden kann.

Gründe für einen Aufruf von delete

Es wird empfohlen, ein DestroyWindow Windows-Objekt zu zerstören, entweder die C++-Methode oder die globale DestroyWindow API.

Rufen Sie die globale DestroyWindow API nicht auf, um ein untergeordnetes MDI-Fenster zu zerstören. Stattdessen sollten Sie die virtuelle Methode CWnd::DestroyWindow verwenden.

Bei C++-Fensterobjekten, die keine automatische sauber up ausführen, kann die Verwendung des delete Operators zu einem Speicherverlust führen, wenn Sie versuchen, den CWnd::~CWnd Destruktor aufzurufenDestroyWindow, wenn dies VTBL nicht auf die korrekt abgeleitete Klasse verweist. Das Leck tritt auf, da das System die entsprechende Zerstörungsmethode nicht finden kann, die aufgerufen werden soll. Die Verwendung DestroyWindow anstelle dieser delete Probleme wird vermieden. Da dieser Fehler subtil sein kann, generiert das Kompilieren im Debugmodus die folgende Warnung, wenn Sie gefährdet sind.

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

Für C++-Windows-Objekte, die automatisch sauber up ausführen, müssen Sie aufrufenDestroyWindow. Wenn Sie den Operator direkt verwenden, benachrichtigt Sie der MFC-Diagnosespeicher-Allocator, dass Sie Arbeitsspeicher zweimal freigeben.If you use the delete operator directly, the MFC diagnostic memory allocator will notify you're two times. Die beiden Vorkommen sind Ihr erster expliziter Aufruf und der indirekte Aufruf delete this; in der automatischen sauber up-Implementierung von PostNcDestroy.

Nachdem Sie ein nicht automatisch sauber up-Objekt aufgerufen DestroyWindow haben, befindet sich das C++-Objekt weiterhin, ist aber m_hWnd vorhandenNULL. Nachdem Sie ein Auto-sauber up-Objekt aufgerufen DestroyWindow haben, ist das C++-Objekt nicht mehr vorhanden und wird vom C++-Löschoperator in der Auto-sauber up-Implementierung freigegebenPostNcDestroy.

Siehe auch

Technische Hinweise nach Nummer
Technische Hinweise nach Kategorie