【问题标题】:default WM_DESTROY not properly cleaning up child windows默认 WM_DESTROY 没有正确清理子窗口
【发布时间】:2010-12-15 15:53:21
【问题描述】:

我有一个用于 Windows Mobile 5 的 WTL 8.0 SDI 应用程序。在下面这个人为的示例中,我创建一个视图,销毁它,然后重新创建它。但是,当它在 WM_INITDIALOG 处理程序中重新创建断言时,由于控件的 HWND 无效。

我注意到我可以通过在 CMyView 中处理 WM_DESTROY 并手动销毁每个子控件来解决此问题。但是,我认为我不应该这样做。 MSDN even says:

此消息首先发送到 窗口被破坏,然后到 子窗口(如果有)原样 销毁。

有人知道发生了什么吗?

编辑:如果我在 CMyView 中处理 WM_NCDESTROY,所有子控件句柄仍然有效! (some_control_.IsWindow()==TRUE) 这不是它应该的样子......

谢谢, 保罗H

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

【问题讨论】:

    标签: c++ winapi wtl


    【解决方案1】:

    创建、销毁和重新创建同一个窗口不是一个好习惯,您应该考虑隐藏它并在再次显示它时重新初始化您的内容。

    无论如何,您的代码在重新创建时不会断言:

    virtual void CMyView::OnFinalMessage(HWND)
    {
        some_control_.m_hWnd = 0;
    }
    

    【讨论】:

    • 从根本上说,因为创建和销毁窗口是一项需要系统操作的操作。实际上是因为 ATL::CWindowImpl 没有正确处理它,所以我们有额外的工作:-)
    【解决方案2】:

    我不是百分百肯定,但好像 some_control_ CEdit 控件没有在父窗口中注册。我认为您将需要调用 some_control_.Create(...) 并将父句柄作为参数。

    有关CEdit::Create() 的文档,请参阅 msdn 文章。

    【讨论】:

    • 这是由我 作为“消息映射和其他标准 WTL 宏”的部分完成的。它旨在包括处理该问题的 DDX_MAP。
    猜你喜欢
    • 2014-05-27
    • 2016-03-11
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 2019-02-14
    • 1970-01-01
    相关资源
    最近更新 更多