默认 WM_DESTROY 未正确清理子窗口
我有一个适用于 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
创建、销毁和重新创建同一个窗口并不是一个好的做法,您应该考虑隐藏它并在再次显示它时重新初始化您的内容。
无论如何,您的代码在重新创建时不会断言:
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:
我不是百分百确定,但似乎 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().