根据这个stackoverflow问题:

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

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

不出所料,这将调用DestroyWindow()

我面临的问题是,按照MSDN,派生的CFormView销毁后:



现在,调用CView析构函数,并在此时执行

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

它在以下断言上失败:ASSERT(::IsWindow(pView->m_hWnd));
我检查了一下,在之前调用的派生CView析构函数中,m_hWnd已经设置为NULL。

我究竟做错了什么 ?

编辑:

这是一个图表,说明了为什么我要发送WM_CLOSE消息而不是WM_QUIT。

c++ - MFC CView(CFormView)销毁崩溃-LMLPHP

我认为答案就在于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:

我发现了问题所在:

第一个 View 的析构函数正在删除未初始化的指针,即UB。这使析构函数挂起并且永远无法完成。

通常,仅在第一个 View 完成时才调用第二个 View 的析构函数。但是在这种情况下,尽管第一个从未完成,但它仍在执行。

由于从不调用第一个 View 基类析构函数,因此从不为第一个 View 调用此函数:
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
}

我们可以在其中看到 View 已从m_viewList 中删除。

这意味着当第二个 View 析构函数完成时,在:
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,但不是。从而导致坠机。

最佳答案

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

关于c++ - MFC CView(CFormView)销毁崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32661010/

10-11 18:05