Этот ответ описывает, как я в конце концов решил свою проблему. Отмечу, что хотя ответ Джона Диблинга был полезным, это не было окончательным решением моей проблемы. Это связано с тем, что сообщение WM_NC_DESTROY отправляется окну как последнее сообщение, но это может быть обработано до того, как будет обработано последнее сообщение окну. См., Например, http://support.microsoft.com/?kbid=202110 для объяснения проблемы.
- DialogProc () вызывается с WM_CLOSE.
- ProcessWindowMessage () вызывает ваш обработчик WM_CLOSE.
- В вашем обработчике WM_CLOSE вы вызываете DestroyWindow ().
- В результате вызов DialogProc снова выполняется с помощью WM_NCDESTROY.
- ProcessWindowMessage () вызывает ваш обработчик WM_NCDESTROY.
- Вы вызываете "удалить это" в своем обработчике WM_NCDESTROY.
После вызова delete this
объект больше не действителен, но вы все еще технически находитесь в обработчике WM_CLOSE
, поэтому вы, вероятно, потерпите крах, когда в конце концов вернетесь туда. Это означает, что на самом деле небезопасно предполагать, что вы можете сделать delete this
в PostNcDestroy, поскольку объект все еще может находиться в каком-то другом кадре стека.
///
/// 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 отличается от PostNcDestroy в окнах MFC тем, что он гарантированно будет вызываться только после завершения работы окончательного обработчика сообщений в стеке.
Затем мы используем подклассы окна, чтобы вставить это окно как процедуру окна для моего собственного окна:
// roughly speaking
FinalMessageWindow<MyWindow> _finalMessageWindow(this);
finalMessageWindow.SubclassWindow(m_hWnd);
Затем мы реализуем обработчик OnFinalMessage для нашего окна:
void MyWindow::OnFinalMessage(HWND hWnd)
{
delete this;
}