ATL CWindow クラスには、OnFinalMessage
ウィンドウの最後のウィンドウ メッセージが処理された後に呼び出される便利な仮想メソッドがあります。この時点で、ウィンドウに関連付けられているオブジェクトを安全に破棄または削除できます。CWnd
MFCクラスから派生したウィンドウに相当するものはありますか?
2 に答える
PostNcDestroy()はあなたが探しているものです。
ところで、モードレス ダイアログを実装していて、「これを削除する」場所を探している場合は、PostNcDestroy() がその場所です。
この回答は、最終的に問題をどのように解決したかを説明しています。John Dibling による回答は役に立ちましたが、これは私の問題に対する最終的な解決策ではありませんでした。これは、WM_NC_DESTROY メッセージがウィンドウへの最終メッセージとして送信されるためですが、これは、ウィンドウへの最後のメッセージの処理が完了する前に処理される可能性があります。問題の説明については、たとえばhttp://support.microsoft.com/?kbid=202110を参照してください。
- DialogProc() は WM_CLOSE で呼び出されます。
- ProcessWindowMessage() は WM_CLOSE ハンドラを呼び出します。
- WM_CLOSE ハンドラーで、DestroyWindow() を呼び出します。
- これにより、WM_NCDESTROY を使用して DialogProc が再度呼び出されます。
- ProcessWindowMessage() は、WM_NCDESTROY ハンドラーを呼び出します。
- WM_NCDESTROY ハンドラで「delete this」を呼び出します。
を呼び出した後delete this
、オブジェクトはもはや有効ではありませんが、技術的にはまだWM_CLOSE
ハンドラーにいるため、最終的にそこに戻ったときにクラッシュする可能性があります。これは、PostNcDestroy で実行できると仮定するのは実際には安全ではないことを意味します。これはdelete this
、オブジェクトがまだ他のスタック フレームに存在している可能性があるためです。
///
/// A window designed to allow any window to use the "OnFinalMessage" method from the ATL CWindow class
/// You must call SubclassWindow for this instance so that the window procedure runs
template<class T>
class FinalMessageWindow : public CWindowImpl<FinalMessageWindow<T> >
{
T *_t; /// The object wanting to receive the final message notification
public:
BEGIN_MSG_MAP(FinalMessageWindow<T>)
END_MSG_MAP()
///
/// The constructor
/// \param t The object that wants to get the OnFinalMessage notification
FinalMessageWindow(T *t)
: _t(t)
{
}
///
/// Called when the final window message for the window has been processed - this is often a good time to delete the object
/// \param hWnd The window handle
virtual void OnFinalMessage(HWND hWnd)
{
_t->OnFinalMessage(hWnd);
}
};
上記のクラスを作成しましたが、これは ATL CWindow クラスから派生していることに注意してください。これにより、このクラスの OnFinalMessage ハンドラーを使用できるようになります。OnFinalMessage ハンドラーは、スタック上の最終メッセージ ハンドラーが完了した後にのみ呼び出されることが保証されているという点で、MFC ウィンドウの PostNcDestroy とは異なります。
次に、ウィンドウのサブクラス化を使用して、このウィンドウを自分のウィンドウのウィンドウ プロシージャとして挿入します。
// roughly speaking
FinalMessageWindow<MyWindow> _finalMessageWindow(this);
finalMessageWindow.SubclassWindow(m_hWnd);
次に、ウィンドウの OnFinalMessage ハンドラーを実装します。
void MyWindow::OnFinalMessage(HWND hWnd)
{
delete this;
}