Эквивалент OnFinalMessage для окон MFC? - PullRequest
1 голос
/ 17 апреля 2009

ATL CWindow класс имеет полезный виртуальный метод OnFinalMessage, который вызывается после обработки последнего сообщения окна для окна - на этом этапе безопасно уничтожать или удалять любые объекты, связанные с окном. Есть ли какой-нибудь эквивалент для окон, полученных из класса MFC CWnd?

Ответы [ 2 ]

4 голосов
/ 17 апреля 2009

PostNcDestroy () - это то, что вы ищете.

Кстати, если вы реализуете немодальное диалоговое окно и ищете, где «удалить это», PostNcDestroy () - это место.

1 голос
/ 17 апреля 2009

Этот ответ описывает, как я в конце концов решил свою проблему. Отмечу, что хотя ответ Джона Диблинга был полезным, это не было окончательным решением моей проблемы. Это связано с тем, что сообщение WM_NC_DESTROY отправляется окну как последнее сообщение, но это может быть обработано до того, как будет обработано последнее сообщение окну. См., Например, http://support.microsoft.com/?kbid=202110 для объяснения проблемы.

  1. DialogProc () вызывается с WM_CLOSE.
  2. ProcessWindowMessage () вызывает ваш обработчик WM_CLOSE.
  3. В вашем обработчике WM_CLOSE вы вызываете DestroyWindow ().
  4. В результате вызов DialogProc снова выполняется с помощью WM_NCDESTROY.
  5. ProcessWindowMessage () вызывает ваш обработчик WM_NCDESTROY.
  6. Вы вызываете "удалить это" в своем обработчике 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;
}
...