默认 WM_DESTROY 未正确清理子窗口

发布于 2024-08-11 08:57:27 字数 2262 浏览 6 评论 0原文

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

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

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

有人知道发生了什么事吗?

编辑:如果我在 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

I have a WTL 8.0 SDI application for Windows Mobile 5. In this contrived example below, I create a view, destroy it, then re-create it. But, when it's re-created assertions in the WM_INITDIALOG handler fail because the control's HWND isn't valid.

I note that I can fix this by handling WM_DESTROY in CMyView and manually destroying every child control. But, I didn't think I should have to. MSDN even says:

This message is sent first to the
window being destroyed and then to the
child windows (if any) as they are
destroyed.

Anybody have an idea as to what's going on?

Edit: If I handle WM_NCDESTROY in CMyView, all of the the child control handles are still valid! (some_control_.IsWindow()==TRUE) That's not how it's supposed to be...

Thanks,
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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

寄离 2024-08-18 08:57:27

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

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

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

It is not good practice to Create, Destroy and re-Create the same window, you should consider hiding it and reinitializing your contents when showing it again.

Anyhow your code will not ASSERT at re-creation with:

virtual void CMyView::OnFinalMessage(HWND)
{
    some_control_.m_hWnd = 0;
}
带上头具痛哭 2024-08-18 08:57:27

我不是百分百确定,但似乎 some_control_ CEdit 控件未在父窗口中注册。我认为您需要使用父句柄作为参数来调用 some_control_.Create(...) 。

请参阅 msdn 文章,了解 CEdit::Create( )

I'm not a hundred percent sure, but it seems like the some_control_ CEdit control is not registered with the parent window. I think you will need to call some_control_.Create(...) with the parent handle as a parameter.

see msdn article for a documentation of CEdit::Create().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文