CMFCBUTTON使用过程中发生内存泄露
来源:互联网 发布:opec原油产量数据 编辑:程序博客网 时间:2024/05/16 02:03
具体的发现过程是:
打开vs2010,新建一个对话框工程,什么都不做,运行,推出的时候看不到内存泄露,但是当你拖一个mfc button到对话框上时,运行程序,推出的时候会看到发生了内存泄露。现在还不知道什么原因。
具体的原因呢是这样的,
首先我们应该从VS2010提供的一些新类,比如CMFCBUTTON的创建过程着手分析。
在CDialog::OnInitDialog()的执行过程中,会调用CMFCControlContainer::SubclassDlgControls()函数对对话框内的各种控件进行初始化,由于VS2010引入了一些新的控件类,这些控件类在本质上又不是新创造出来的类,而是原来的一些类的子类,比如CMFCBUTTON就是CButton的一个子类,这样在一个CMFCBUTTON创建的时候就需要进行一次重子类化的过程。
详细的跟踪过程如下:
0. CDialog::OnInitDialog()函数会创建对话框界面上的控件,然后把这些对象保存起来。这个时候如果对话框模板被定义了会执
行ExecuteDlgInit()函数。
1. ExecuteDlgInit()函数会调用CMFCControlContainer::SubclassDlgControls()开始子类化对话框内的控件。
2. 接下来CMFCControlContainer::CreateDlgControl()函数被调用,会创建一个CMFCBUTTON对象。
3. 然后会将该CMFCBUTTON对象进行子类化SubclassWindow()。
4. 然后会进入CMFCBUTTON对象的PreSubclassWindow()函数,这个函数基本上没有做什么事情。
5. 然后函数返回到ExecuteDlgInit()函数,这个时候对话框会发送一个WM_MFC_INITCTRL消息给该CMFCBUTTON对象。也就
是在这个时候CMFCBUTTON对象的消息提示控件m_pToolTip第一次被创建。
而这个创建的过程是委托给一个CTooltipManager类来管理的,这个类会将当前创建消息提示控件m_pToolTip的窗口(也就
是m_pToolTip的父窗口)的句柄记录下来。
6. 然后到了CWnd::UpdateData()函数,他用于更新和控件绑定的数据,接下来到了DoDataExchange(CDataExchange* pDX)
函数,然后是DDX_Control(pDX, IDC_MFCBUTTON1, mfcbut)函数,在这个函数中会重新子类化控件,即
CMFCControlContainer* pMFCCtrlContainer = pDX->m_pDlgWnd->GetMFCControlContainer();
if (pMFCCtrlContainer != NULL && pMFCCtrlContainer->IsSubclassedFeaturePackControl(hWndCtrl))
{
pMFCCtrlContainer->ReSubclassControl(hWndCtrl, (WORD)nIDC, rControl);
return;
}7. 然后消息又走到了CMFCBUTTON对象的PreSubclassWindow()函数。
8. 子类化成功后CMFCControlContainer类又会发送一个WM_MFC_INITCTRL消息。又对m_pToolTip进行了初始化。
然而在该CMFCBUTTON对象被销毁的时候即OnDestroy()中,会把最后一次创建的m_pToolTip对象删除。这貌似不合逻辑,似乎少删除了一个m_pToolTip对象。
然也!
我想了很久才发现,第一次子类化的时候用到的CMFCBUTTON对象是我们不绑定任何数据的对象,而第二次用到的才是我们定义的CMFCBUTTON对象。那么按照顺序就是“开始的控件”-子类化-“第一个控件”--子类化--“第二个控件”,实际上第二次子类化的并不是最开始的那个对象。而实际上“第一个控件”和“第二个控件”的句柄是相同的,那么在“delete”的时候只会销毁第二次生成的“m_pToolTip”,第一次的没有被销毁。这样就合理了。
解决的办法有两种就是:
1.动态创建CMFCBUTTON对象。
2.修改DoDataExchange函数,主要是重载DDX_Control函数,在其中销毁tooltip控件。当你确定在使用CMFCButton的时候,可以调用这个函数。
void MFC_DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);TCHAR lpszClassName [MAX_CLASS_NAME + 1];
::GetClassName(hWndCtrl, lpszClassName, MAX_CLASS_NAME);CString strClass = lpszClassName;
if (strClass == _T("MFCButton"))
{
CMFCButton *pMFCButton = (CMFCButton *)pDX->m_pDlgWnd->GetDlgItem(nIDC);
CToolTipCtrl& pToolTipCtrl = pMFCButton->GetToolTipCtrl();
if (pToolTipCtrl.m_hWnd != NULL)
{
CToolTipCtrl* pCtrl = &pToolTipCtrl;
CTooltipManager::DeleteToolTip(pCtrl);
}
}DDX_Control(pDX, nIDC, rControl);
}void CShrinkWndDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);MFC_DDX_Control(pDX, IDC_MFCBUTTON1, mfcbut);
}
- CMFCBUTTON使用过程中发生内存泄露
- MFC中使用CMFCBUTTON按钮关闭对话框出现内存泄漏
- BSTR在使用过程中为什么会内存泄露呢
- JAVA程序中也可能会发生内存泄露的问题
- 小心使用定时器时发生的内存泄露
- CString使用AllocSysString函数时发生内存泄露
- CMFCButton内存泄漏
- android开发过程中避免内存泄露
- Android开发过程中内存泄露检测
- Android开发过程中内存泄露检测
- MFC中CMFCButton类改变颜色的使用
- CMFCButton使用简介
- OpenCV使用中“内存泄露”的探索
- Android中使用Handler造成内存泄露
- Android中使用Handler造成内存泄露
- CMFCButton
- CMFCBUTTON
- JAVA 是否会发生内存泄露
- 强大的git
- (6)Hive 高级编程——深入浅出学Hive
- 【笔记】javascript正则表达式的预查分类
- Qt之打包发布(NSIS详解)
- jQuery UI Datepicker中文显示
- CMFCBUTTON使用过程中发生内存泄露
- 电脑知识硬件普及
- Choose a destination with a supported architecture in order to run on this device.
- 美食菜谱将会成创业风口的两大理由
- mysql进入命令
- 用java实现邮件服务的几种方式总结
- iOS开发ASIHttpRequest介绍(七)-- ASIHTTPRequest断点续传(下载)
- Android的UAProfe和UA String
- can总线的示波器检测方法