Я работаю над приложением 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 — это класс, унаследованный от StandardDialog, который унаследован от CDialog. Сейчас я буду публиковать только фрагменты кода, так как этот пост уже слишком длинный (если вам нужно больше, скажите мне, какая часть может быть интересна)... Диалоговое окно, которое предлагает возможность закрыть приложение, называется 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 я получаю нарушение прав доступа. Программа не останавливается, просто строка в окне вывода. Он продолжается оператором «вернуть FALSE;» в SWinApp InitInstance().
Я знаю, что нарушение прав доступа происходит при двойном удалении объекта или использовании указателя, когда зависимый объект уже был уничтожен, но я не могу понять, что здесь происходит не так. Кроме того, я должен сказать, что 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;
}
Но нарушение все еще происходит... Я искал окно стека вызовов, но не смог найти его на вкладке просмотра... Прошу прощения за такой длинный пост! И извините, если это слишком специфично... Но я борюсь уже несколько часов и понятия не имею, что я могу попробовать... Любая помощь приветствуется!