по умолчанию WM_DESTROY неправильно очищает дочерние окна - PullRequest
1 голос
/ 12 ноября 2009

У меня есть приложение WTL 8.0 SDI для Windows Mobile 5. В этом надуманном примере ниже я создаю представление, уничтожаю его, а затем воссоздаю. Но при повторном создании утверждений в обработчике WM_INITDIALOG происходит сбой, поскольку HWND элемента управления недопустим.

Хочу заметить, что я могу это исправить, обработав WM_DESTROY в CMyView и вручную уничтожив каждый дочерний элемент управления. Но я не думал, что должен был. MSDN даже говорит :

Это сообщение отправляется первым окно разрушается, а затем к дочерние окна (если есть) как они есть уничтожены.

Кто-нибудь имеет представление о том, что происходит?

Редактировать: если я обработаю WM_NCDESTROY в CMyView, все дочерние дескрипторы управления все еще действительны! (some_control_.IsWindow()==TRUE) Это не так, как должно быть ...

Спасибо, PaulH

class CMyView : public CDialogImpl< CMyView >,
                public CWinDataExchange< CMyView >
{
    // <snip> Message Map and other standard WTL macros </snip>

    LRESULT OnInitDialog( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
    {
        DoDataExchange( FALSE );
        // assertion fails within the SetWindowText() call
        // atlwin.h line 876
        // ATLASSERT(::IsWindow(m_hWnd));
        some_control_.SetWindowText( _T( "Foo" ) );
        return 0;
    };

private:
    CEdit some_control_;
}; // class CMyView

class CMainFrame : public CFrameWindowImpl< CMainFrame >, 
                   public CUpdateUI< CMainFrame >,
                   public CMessageFilter, 
                   public CIdleHandler
{
public:
    // <snip> Message Map and other standard WTL macros </snip>

    BOOL CMainFrame::PreTranslateMessage( MSG* pMsg )
    {
        if( CFrameWindowImpl< CMainFrame >::PreTranslateMessage( pMsg ) )
            return TRUE;

        return my_view_.PreTranslateMessage( pMsg );
    };

    LRESULT OnCreate( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
    {
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        ATLASSERT( pLoop != NULL );
        pLoop->AddMessageFilter( this );
        pLoop->AddIdleHandler( this );

        m_hWndClient = my_view_.Create( m_hWnd );
        my_view_.DestroyWindow();
        m_hWndClient = my_view_.Create( m_hWnd );
    };

private:
    CMyView my_view_;
}; // class CMainFrame

Ответы [ 2 ]

0 голосов
/ 06 марта 2010

Не рекомендуется создавать, уничтожать и заново создавать одно и то же окно, вам следует подумать о том, чтобы скрыть его и повторно инициализировать содержимое при повторном его отображении.

Во всяком случае, ваш код не будет ASSERT при повторном создании с:

virtual void CMyView::OnFinalMessage(HWND)
{
    some_control_.m_hWnd = 0;
}
0 голосов
/ 09 декабря 2009

Я не уверен на сто процентов, но похоже, что элемент управления some_control_ CEdit не зарегистрирован в родительском окне. Я думаю, вам нужно будет вызвать some_control_.Create (...) с родительским дескриптором в качестве параметра.

см. Статью msdn для документации CEdit :: Create () .

...