在 mfc 应用程序结束后从 CMainFrame 调用析构函数时发生访问冲突

Access violation at destructor call from CMainFrame after end of mfc application

我正在为嵌入式 compact 开发一个 mfc 应用程序。目前我尝试添加一个对话框来关闭程序。我的问题是我在 CMainFrame 的析构函数调用中遇到访问冲突。 为了更清楚先一段代码。 这是我的应用程序的起点:

SWinApp.h

class SWinApp : public CWinApp
{
public:
    SWinApp();
    ~SWinApp(){};
public:
    virtual BOOL InitInstance();

protected:
    DECLARE_MESSAGE_MAP()
};

SWinApp.cpp

SWinApp::SWinApp():CWinApp()
{
}

BOOL SWinApp::InitInstance()
{
    CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( SMainFrame );
    CObject* pObject = pRuntimeClass->CreateObject();
    ASSERT( pObject->IsKindOf( RUNTIME_CLASS( SMainFrame ) ) );
    m_pMainWnd = (SMainFrame*)pObject;
    m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
    return FALSE; // this is the next executed line after the access violation
}

BEGIN_MESSAGE_MAP(SWinApp, CWinApp)
END_MESSAGE_MAP()

SMainFrame.h

class SMainFrame : public CFrameWnd
{
    DECLARE_DYNCREATE(SMainFrame)
protected:
    SMainFrame();           
    ~SMainFrame();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

    afx_msg LRESULT OnDialogReady(WPARAM wParam, LPARAM lParam);

    afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);

    CurrentData* GetCurrentData(){return this->currentData;};
    Configuration* GetConfiguration(){return this->configuration;};
private:
    BOOL m_shown;   
    CurrentData* currentData;
    Configuration* configuration;
    std::map<UINT, CDialog*> views;
    UINT currentID;
};

SMainFrame.cpp

IMPLEMENT_DYNCREATE(SMainFrame, CFrameWnd)

    SMainFrame::SMainFrame()
{
    CString appName;
    appName.LoadStringW(IDS_APP_NAME);
    Create(NULL, appName);
    m_shown = FALSE;
    this->configuration = new Configuration();
    this->currentData = new CurrentData();
    this->currentID = IDD_MAIN_MENU_DIALOG;
    views.insert(std::make_pair(IDD_MAIN_MENU_DIALOG, new MainMenuDialog(this->configuration, this->currentData)));
    // There are more dialogs but for tests one is enough

}

SMainFrame::~SMainFrame()
{
    for(auto iterator:views)
    {
        delete iterator.second;
    }
    delete this->configuration;
    delete this->currentData; //Is executed properly
} // After this line an access violation occurres...


BEGIN_MESSAGE_MAP(SMainFrame, CFrameWnd)
    ON_MESSAGE(WM_USER_DIALOG_READY, &SMainFrame::OnDialogReady)
    ON_WM_CREATE()
    ON_WM_ACTIVATE()
END_MESSAGE_MAP()

// SMainFrame message handlers

int SMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ModifyStyle(WS_CAPTION, 0, SWP_DRAWFRAME | SWP_NOZORDER );

    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    return 0;
}
afx_msg LRESULT SMainFrame::OnDialogReady(WPARAM wParam, LPARAM lParam)
{
    DialogThreadParams* params = (DialogThreadParams*)lParam;
    this->currentID = params->nextDialogID;
    m_shown = FALSE;
    this->ActivateFrame();
    return 0;
}

BOOL SMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;

    cs.dwExStyle &= ~WS_EX_CLIENTEDGE | SWP_DRAWFRAME; 
    cs.style  =  WS_EX_CLIENTEDGE; 

    return TRUE;
}

void SMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{

    if(m_shown == FALSE)
    {
        m_shown = TRUE; 
        if(IsWindow(views[currentID]->m_hWnd))
        {
            views[currentID]->SetFocus();
        }
        else
        {
            views[currentID]->DoModal();
        }
    }
    CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
}

MainMenuDialog是class继承自StandardDialog,而StandardDialog又继承自CDialog。我现在只 post 部分代码,因为这个 post 已经太长了(如果你需要更多,请告诉我哪一部分可能很有趣)...... 提供关闭应用程序的可能性的对话框称为 ShutdownDialog(仅继承自 CDialog)并存储为 MainMenuDialog 的私有变量:

ShutdownDialog* shutdownDialog;

在 MainMenuDialog 的构造函数中创建:

this->shutdownDialog = new ShutdownDialog();

我在单击按钮时显示对话框:

void MainMenuDialog::OnClickedShutdownButton()
{
    shutdownDialog->DoModal();
}

并在 MainMenuDialog 的析构函数中被删除:

MainMenuDialog::~MainMenuDialog()
{
    delete shutdownDialog;
}

在 ShutdowDialog 中,我用这段代码关闭了应用程序:

AfxGetMainWnd()->PostMessage(WM_CLOSE);
EndDialog( 0 );

在此之前一切正常。应用程序开始销毁对象。但是在完成对 SMainFrame 析构函数的调用后,我遇到了访问冲突。程序并没有停止,只是输出 window 中的一行。它继续在 SWinApp InitInstance().

中声明 "return FALSE;"

我知道当两次删除一个对象或使用一个依赖对象已经被销毁的指针时会发生访问冲突,但我不知道这里出了什么问题。另外我不得不说 SWinApp 和 SMainFrame 是由一位同事创建的,我用 SMainFrame 中的对话框修改了部分。 我认为 m_pMainWnd 可能是问题所在,因为在析构函数调用 SMainFrame 之后它一定是一个无效指针。所以我尝试了:

SMainFrame::~SMainFrame()
{
    for(auto iterator:views)
    {
        delete iterator.second;
    }
    delete this->configuration;
    delete this->currentData;
    AfxGetApp()->m_pMainWnd = NULL;
}

但是违规还是发生了... 我搜索了 Callstack Window 但在视图选项卡下找不到它... 抱歉了这么久post! 对不起,如果这太具体了……但我已经苦苦挣扎了几个小时,不知道我能尝试什么……欢迎任何帮助!

AfxGetMainWnd()->PostMessage(WM_CLOSE);更改为::PostQuitMessage( 0 );