MFC CView(CFormView)破坏崩溃

时间:2015-09-18 21:03:51

标签: c++ mfc destructor

根据此stackoverflow问题:

What is the correct way to programmatically quit an MFC application?

我正在使用AfxGetMainWnd()->PostMessage(WM_CLOSE,0,0);退出MFC程序。 (SDI,CFrameWnd包含带有两个CFormViews的CSplitterWnd)

正如所料,这会调用DestroyWindow()

我遇到的问题是在导出的CFormView销毁之后,根据MSDN:

  

在非自动清理对象上调用DestroyWindow后,C ++对象仍然存在,但m_hWnd将为NULL。 [MSDN]

现在调用CView析构函数,然后执行

CDocument::RemoveView()...
CDocument::UpdateFrameCounts()

它在以下断言上失败:ASSERT(::IsWindow(pView->m_hWnd));

我检查过,在之前调用的派生CView析构函数中m_hWnd已经设置为NULL。

我做错了什么?

编辑:

这是一个图表,说明我想发送WM_CLOSE消息而不是WM_QUIT的原因。

enter image description here

我认为答案存在于MSDN Technical Note中,但我无法弄明白。

编辑2:

调用事物的顺序:

1- AfxGetMainWnd()->PostMessage(WM_CLOSE,0,0);

2- Derived CFrameWnd::OnClose()

3- CFrameWnd::OnClose()

调用CWinApp::CloseAllDocuments(BOOL bEndSession);

调用CDocManager::CloseAllDocuments(BOOL bEndSession)

调用CDocTemplate::CloseAllDocuments(BOOL)

调用CDocument::OnCloseDocument()

现在,在这个函数中

while (!m_viewList.IsEmpty())
{
    // get frame attached to the view
    CView* pView = (CView*)m_viewList.GetHead();
    ASSERT_VALID(pView);
    CFrameWnd* pFrame = pView->EnsureParentFrame();

    // and close it
    PreCloseFrame(pFrame);
    pFrame->DestroyWindow();
    // will destroy the view as well
}

所以我们看到CWnd::DestroyWindow()被调用,所以:

4- Derived CFormView destructor

5- CScrollView::~CScrollView()

6- CView::~CView()

调用CDocument::RemoveView(CView* pView)

调用CDocument::OnChangedViewList()

调用CDocument::UpdateFrameCounts()

此处崩溃:ASSERT(::IsWindow(pView->m_hWnd));

因为pView->m_hWndNULL ...

编辑3:

我弄清楚问题是什么:

第一个视图的析构函数是删除未初始化的指针,即UB。这使析构函数挂起并永远不会完成。

通常,第二个视图的析构函数仅在完成第一个视图时被调用。但在这种情况下它仍然被执行,虽然第一个从未完成。

由于从未调用过第一个视图基类析构函数,因此从未为第一个视图调用此函数:

void CDocument::RemoveView(CView* pView)
{
    ASSERT_VALID(pView);
    ASSERT(pView->m_pDocument == this); // must be attached to us

    m_viewList.RemoveAt(m_viewList.Find(pView));
    pView->m_pDocument = NULL;

    OnChangedViewList();    // must be the last thing done to the document
}

我们可以看到该视图已从m_viewList 中删除。

这意味着当第二个视图析构函数完成时,在:

void CDocument::UpdateFrameCounts()
     // assumes 1 doc per frame
{
    // walk all frames of views (mark and sweep approach)
    POSITION pos = GetFirstViewPosition();
    while (pos != NULL)
    {
...

该pos应该是NULL,但事实并非如此。导致崩溃的原因。

3 个答案:

答案 0 :(得分:2)

我认为你关闭框架的方式不是那里的问题。 我的猜测是你手动销毁其中一个视图,而你应该让MFC删除它们(你可能在其中一个上调用DestroyWindow)

答案 1 :(得分:1)

致电::PostQuitMessage(0);关闭应用。

答案 2 :(得分:0)

问题已解决,请参阅问题解答中的编辑3.