如何 'properly close MFC Modeless Dialogs and fixing resource leak'
How to 'properly close MFC Modeless Dialogs and fixing resource leak'
我创建了一个 MFC 应用程序,其中有一个 Base Dialog
(派生自 CDialog
class)、一个 Setting Dialog
(派生自 CBaseDlg
和App Dialog
(也源自 CBaseDlg
)。然后我创建了一个名为 CScrMng
(又名屏幕管理器)的 class,它包含 ShowDialog()
函数(到 Create
和 Show
这些对话框)。
基本思路是 ScrMng
将管理我所有的无模式对话框,任何时候我想打开一个对话框,我只需要在 BaseDlg.cpp
中 CScrMng::ShowDialog()
,然后对话框将显示。
这种方法导致资源到处泄漏。我对覆盖 PostNcDestroy()
做了一些研究,但我不清楚在哪里调用它。
我应该使用什么函数来正确关闭这些无模式对话框?
我想从 Base Dialog
打开 Setting Dialog
,然后当我点击 Cancel
按钮时,它应该 return 我到 Base Dialog
屏幕,以便我可以打开另一个对话框。
现在我正在使用 EndDialog()
。我知道这是错误的,但是调用DestroyWindow()
会立即退出程序,这不是我想要的。
源代码
MFCApplication.cpp
#include...
BEGIN_MESSAGE_MAP(CMFCApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
CMFCApp::CMFCApp()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
}
CMFCApp theApp;
BOOL CMFCApp::InitInstance()
{
...
CWinApp::InitInstance();
CShellManager *pShellManager = new CShellManager;
CScrMng::GetInstance()->ShowDialog(IDD_MAINDLG);
SetRegistryKey(_T("Local Applications"));
if (pShellManager != NULL)
{
delete pShellManager;
}
return TRUE;
}
CScrMng.cpp
#include...
CScrMng* CScrMng::m_pInstance = NULL;
CScrMng* CScrMng::GetInstance(){
if (m_pInstance == NULL)
m_pInstance = new CScrMng();
return m_pInstance;
}
CScrMng::CScrMng(){}
void CScrMng::ShowDialog(int ID)
{
CMainDlg* m_pDlg = NULL;
switch (ID)
{
case IDD_MAINDLG:
m_pDlg = new CMainDlg();
theApp.m_pMainWnd = m_pDlg;
m_pDlg->Create(IDD_MAINDLG);
m_pDlg->ShowWindow(SW_SHOW);
m_pDlg->UpdateWindow();
break;
case ...
break;
case IDD_SETTINGDLG:
m_pDlg = new CSettingDlg();
m_pDlg->Create(ID,NULL);
m_pDlg->ShowWindow(SW_SHOW);
m_pDlg->UpdateWindow();
break;
}
CMainDlg.cpp
#include...
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent) {m_hIcon = AfxGetApp()-> LoadIcon(IDR_MAINFRAME);}
void CMainDlg::DoDataExchange(CDataExchange* pDX) {...}
void CMainDlg::PostNcDestroy() //Added these
{
CDialog::PostNcDestroy();
delete this;
}
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
...
END_MESSAGE_MAP()
BOOL CMainDlg::OnInitDialog() {
CDialog::OnInitDialog();
SetIcon(m_hIcon, FALSE);
return TRUE;
}
void CMainDlg::OnPaint() {...}
void CMainDlg::OnBnClickedOpenAppdlg()
{
CScrMng::GetInstance()->ShowDialog(IDD_APPDLG);
}
void CMainDlg::OnBnClickedOpenSettingdlg()
{
CScrMng::GetInstance()->ShowDialog(IDD_SETTINGDLG);
}
void CMainDlg::OnBnClickedExit()
{
DestroyWindow(); //replaced CDialog::OnCancel() with this.
}
更新:更改 SettingDlg.cpp 中的代码后,我遇到了 Debug Assertion Failed!
问题:
void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)
{
ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL)); //Breakpoint triggered
if (m_pCtrlSite == NULL)
::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint);
else
m_pCtrlSite->MoveWindow(x, y, nWidth, nHeight);
}
以下是我在 .cpp 文件中所做的更改:
SettingDlg.cpp
void CSettingDlg::PostNcDestroy()
{
CMainDlg::PostNcDestroy();
}
void CSettingDlg::OnBnClickedSettingcancel()
{
DestroyWindow(); //Using destroyWindow rather than EndDialog();
}
关闭并删除无模式对话框。
正确的方法是:为无模式对话框覆盖 PostNcDestroy、OnOk() 和 OnCancel()
void CBaseDlg::PostNcDestroy()
{
CDialog::PostNcDestroy();
delete this;
}
。
void CBaseDlg::OnOk()
{
if(!UpdateData(TRUE))
return;
DestroyWindow();
}
.
void CBaseDlg::OnCancel()
{
DestroyWindow();
}
我创建了一个 MFC 应用程序,其中有一个 Base Dialog
(派生自 CDialog
class)、一个 Setting Dialog
(派生自 CBaseDlg
和App Dialog
(也源自 CBaseDlg
)。然后我创建了一个名为 CScrMng
(又名屏幕管理器)的 class,它包含 ShowDialog()
函数(到 Create
和 Show
这些对话框)。
基本思路是 ScrMng
将管理我所有的无模式对话框,任何时候我想打开一个对话框,我只需要在 BaseDlg.cpp
中 CScrMng::ShowDialog()
,然后对话框将显示。
这种方法导致资源到处泄漏。我对覆盖 PostNcDestroy()
做了一些研究,但我不清楚在哪里调用它。
我应该使用什么函数来正确关闭这些无模式对话框?
我想从 Base Dialog
打开 Setting Dialog
,然后当我点击 Cancel
按钮时,它应该 return 我到 Base Dialog
屏幕,以便我可以打开另一个对话框。
现在我正在使用 EndDialog()
。我知道这是错误的,但是调用DestroyWindow()
会立即退出程序,这不是我想要的。
源代码
MFCApplication.cpp
#include...
BEGIN_MESSAGE_MAP(CMFCApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
CMFCApp::CMFCApp()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
}
CMFCApp theApp;
BOOL CMFCApp::InitInstance()
{
...
CWinApp::InitInstance();
CShellManager *pShellManager = new CShellManager;
CScrMng::GetInstance()->ShowDialog(IDD_MAINDLG);
SetRegistryKey(_T("Local Applications"));
if (pShellManager != NULL)
{
delete pShellManager;
}
return TRUE;
}
CScrMng.cpp
#include...
CScrMng* CScrMng::m_pInstance = NULL;
CScrMng* CScrMng::GetInstance(){
if (m_pInstance == NULL)
m_pInstance = new CScrMng();
return m_pInstance;
}
CScrMng::CScrMng(){}
void CScrMng::ShowDialog(int ID)
{
CMainDlg* m_pDlg = NULL;
switch (ID)
{
case IDD_MAINDLG:
m_pDlg = new CMainDlg();
theApp.m_pMainWnd = m_pDlg;
m_pDlg->Create(IDD_MAINDLG);
m_pDlg->ShowWindow(SW_SHOW);
m_pDlg->UpdateWindow();
break;
case ...
break;
case IDD_SETTINGDLG:
m_pDlg = new CSettingDlg();
m_pDlg->Create(ID,NULL);
m_pDlg->ShowWindow(SW_SHOW);
m_pDlg->UpdateWindow();
break;
}
CMainDlg.cpp
#include...
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent) {m_hIcon = AfxGetApp()-> LoadIcon(IDR_MAINFRAME);}
void CMainDlg::DoDataExchange(CDataExchange* pDX) {...}
void CMainDlg::PostNcDestroy() //Added these
{
CDialog::PostNcDestroy();
delete this;
}
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
...
END_MESSAGE_MAP()
BOOL CMainDlg::OnInitDialog() {
CDialog::OnInitDialog();
SetIcon(m_hIcon, FALSE);
return TRUE;
}
void CMainDlg::OnPaint() {...}
void CMainDlg::OnBnClickedOpenAppdlg()
{
CScrMng::GetInstance()->ShowDialog(IDD_APPDLG);
}
void CMainDlg::OnBnClickedOpenSettingdlg()
{
CScrMng::GetInstance()->ShowDialog(IDD_SETTINGDLG);
}
void CMainDlg::OnBnClickedExit()
{
DestroyWindow(); //replaced CDialog::OnCancel() with this.
}
更新:更改 SettingDlg.cpp 中的代码后,我遇到了 Debug Assertion Failed!
问题:
void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)
{
ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL)); //Breakpoint triggered
if (m_pCtrlSite == NULL)
::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint);
else
m_pCtrlSite->MoveWindow(x, y, nWidth, nHeight);
}
以下是我在 .cpp 文件中所做的更改: SettingDlg.cpp
void CSettingDlg::PostNcDestroy()
{
CMainDlg::PostNcDestroy();
}
void CSettingDlg::OnBnClickedSettingcancel()
{
DestroyWindow(); //Using destroyWindow rather than EndDialog();
}
关闭并删除无模式对话框。
正确的方法是:为无模式对话框覆盖 PostNcDestroy、OnOk() 和 OnCancel()
void CBaseDlg::PostNcDestroy()
{
CDialog::PostNcDestroy();
delete this;
}
。
void CBaseDlg::OnOk()
{
if(!UpdateData(TRUE))
return;
DestroyWindow();
}
.
void CBaseDlg::OnCancel()
{
DestroyWindow();
}