テクニカル ノート 17: ウィンドウ オブジェクトの破棄
ここでは、 CWnd::PostNcDestroy のメソッドの使用について説明します。CWndのカスタマイズされたアロケーション派生オブジェクトを行う場合は、このメソッドを使用します。ここでは、 delete 演算子の代わりに、 C.C++ のペイン オブジェクトを破棄するには、理由 CWnd::DestroyWindow を使用する必要があるかを示します。
このトピックのガイドラインに従う場合は、いくつかのクリーンアップ問題があります。これらの問題は削除を忘れているかまたはフリー C++ の、 HWNDの秒のようなシステム リソースを解放するのを忘れているかメモリ事項に、は、多数の時間解放されるオブジェクトが発生する可能性があります。
問題
各ペイン オブジェクト ( CWndから派生したクラスのオブジェクト)は、どちらの C.C++ のオブジェクトと HWNDを表します。C++ オブジェクトは、アプリケーションのヒープ上に割り当てられ、 HWNDの秒はウィンドウ マネージャーによってシステム リソースに割り当てられます。ペイン オブジェクトを破棄するいくつかの方法があるため、システム リソースまたはメモリ リークを防ぐ規則のセットを提供する必要があります。これらの規則は、オブジェクトとウィンドウ ハンドルが 1 回以上破棄されるのを防ぐ必要があります。
分割ウィンドウ
次に、ペイン オブジェクトを破棄するには 2 とおりの許可されています:
CWnd::DestroyWindow または Windows API DestroyWindowを呼び出します。
delete 演算子と明示的に削除します。
最初のケースははるかに一般的です。このケースは、コードが DestroyWindow を直接ダイヤルしなくても適用されます。ユーザーが直接フレーム ウィンドウを閉じると、この操作は WM_CLOSE のメッセージを生成し、このメッセージへの既定の応答が親ウィンドウが破棄されるとダイヤルするすべての子の DestroyWindow を DestroyWindow.、ウィンドウをダイヤルすることです。
2 番目のケース、ウィンドウ オブジェクトの delete 演算子の使用は、まれである必要があります。次に delete を使用するケースです。正しい可能です。
CWnd::PostNcDestroy の自動クリーンアップ
システムがペインを破棄すると、ウィンドウに送信最後のウィンドウ メッセージは WM_NCDESTROYです。そのメッセージの既定の CWnd ハンドラーは CWnd::OnNcDestroyです。OnNcDestroy は C++ オブジェクトから HWND をデタッチし、仮想関数 PostNcDestroyをダイヤルします。あるクラスは、 C++ オブジェクトを削除するには、この関数をオーバーライドします。
CWnd::PostNcDestroy の既定の実装は、スタック フレームに割り当てられているか、または他のオブジェクトに埋め込まれているペイン オブジェクトに適した何も実行しません。これにより、他のオブジェクトを持たないヒープ上に割り当てられたように設計されたウィンドウ オブジェクトに対して適切ではありません。つまり、他の C++ オブジェクトに埋め込まれていないウィンドウ オブジェクトに対して適切ではありません。
delete thisを実行 PostNcDestroy ヒープのメソッドのオーバーライドに、割り当てられるように設計された要素のクラス。このステートメントは、 C++ オブジェクトに関連付けられているメモリを解放します。m_hWnd が null 以外で既定の CWnd のデストラクターが DestroyWindow をダイヤルするが、これは無限再帰のハンドルがデタッチ クリーンアップ フェーズの間に空白であるため、原因はありません。
[!メモ]
システムは、通常、 Windows の WM_NCDESTROY のメッセージを処理し、 HWND および C++ のペイン オブジェクトが既に接続されていない後 CWnd::PostNcDestroy をダイヤルします。システムは、失敗が発生すると CWnd::Create のほとんどの呼び出しの実装の CWnd::PostNcDestroy をダイヤルします。自動クリーンアップの規則は、このトピックの後半で説明します。
自動クリーンアップのクラス
次のクラスは自動クリーンアップのようには設計されていません。別の C++ オブジェクトまたはスタックで一般的に埋め込まれます:
すべての標準のウィンドウ コントロール (CStatic、 CEdit、 CListBoxなど)。
CWnd (たとえば、カスタム コントロール)から直接派生した子ウィンドウ。
分割ウィンドウ (CSplitterWnd)。
既定のコントロール バーの ( CControlBarから派生したクラスは、コントロール バー オブジェクトの自動削除を有効にする方法は テクニカル ノート 31 が表示されます)。
スタック フレームのモーダル ダイアログ用に設計されたダイアログCDialog()。
すべての標準ダイアログは CFindReplaceDialogを除く。
ClassWizard で作成された既定のダイアログ ボックス。
次のクラスは自動クリーンアップするためにデザインされています。これらはヒープで通常、単独で使用:
メイン フレーム ウィンドウ ( CFrameWndから直接または間接的に派生します)。
ビュー] ウィンドウ ( CViewから直接または間接的に派生します)。
これらの規則を中断する場合は、派生クラスの PostNcDestroy のメソッドをオーバーライドします。クラスに自動クリーンアップを追加するには、基本クラスをダイヤルし、を delete thisします。クラスから自動クリーンアップを削除するには、直接基本クラスの PostNcDestroy メソッドの代わりに CWnd::PostNcDestroy を直接ダイヤルします。
自動クリーンアップの動作を変更するほとんどの一般的な用途は、ヒープに割り当てることができるモードレス ダイアログを作成します。
いつ削除を呼び出します。
これは、ペイン オブジェクトを破棄するに DestroyWindow を C++ のメソッドや DestroyWindow のグローバルな API ダイヤルすることをお勧めします。
MDI 子ウィンドウを破棄するに DestroyWindow のグローバルな API をダイヤルしないでください。仮想メソッド CWnd::DestroyWindow を代わりに使用する必要があります。
自動クリーンアップを実行 delete 演算子を使用して C++ のペイン オブジェクトに VTBL を派生クラスに正しく指して CWnd::~CWnd のデストラクターの DestroyWindow をダイヤルするときに、メモリ リークが発生することがあります。これは、システムがダイヤルする適切な破棄メソッドを検出できないためです。delete の代わりに DestroyWindow を使用してこれらの問題を回避できます。これが明確でないエラーになるため、デバッグ モードでコンパイルはリスクがある場合は、次の警告が生成されます。
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
自動クリーンアップを実行する C++ のペイン オブジェクトの場合、 DestroyWindowをダイヤルします。delete の演算子を直接使用すると、 MFC 診断メモリ アロケーターが 2 回メモリを解放する通知します。2 回の繰り返しは PostNcDestroyの自動クリーンアップの実装の delete this に明示的な呼び出し、間接呼び出しです。
自動非クリーンアップのオブジェクトの DestroyWindow を呼び出した後、 C++ オブジェクトが存在します m_hWnd 、は null です。自動クリーンアップのオブジェクトの DestroyWindow を呼び出した後、 C++ のオブジェクトは、 PostNcDestroyの自動クリーンアップを実装する C++ の削除操作によってよって解放したされます。