簡體   English   中英

MFC CView(CFormView)破壞崩潰

[英]MFC CView (CFormView) destruction crash

根據這個stackoverflow問題:

以編程方式退出MFC應用程序的正確方法是什么?

我正在使用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的原因。

在此輸入圖像描述

我認為這個答案存在於MSDN技術說明中 ,但我無法弄清楚。

編輯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 ,但事實並非如此。 導致崩潰的原因。

我認為你關閉框架的方式不是那里的問題。 我的猜測是你手動銷毀其中一個視圖,而你應該讓MFC刪除它們(你可能在其中一個上調用了DestroyWindow)

Call ::PostQuitMessage(0); 關閉應用程序。

問題已解決,請參閱問題解答中的編輯3。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM