关于CHTMLView有内存泄漏的问题及解决办法
应用 CHtmlView 类,发现过一个问题,CHtmlView创建的页面如果有flash或者是其他背景音乐的时候, 当关闭这个页面,背景音乐还是在响,这就说明CHtmlView关闭的时候,并没有正确的释放加载进来的资源。 在1.17版本的JJIE浏览器中, 就存在着这样的一个问题。我也是偶然发现的。 于是我上网查了一下, 发现CHtmlView确实存在着资源释放的问题: 存在内存泄漏的函数如下: • Navigate • GetFullName • GetType • GetLocationName • GetLocationURL • LoadFromResource(LPCTSTR lpszResource) • LoadFromResource(UINT nRes) 在前五个函数中, 都有着这样一个函数 SysFreeString, 但是这个函数是需要BSTR支持的。如果我们网页上的资源不是Unicode格式的,我们在使用SysFreeString的时候就不能正确的释放资源,从而导致内存泄露。 后两者导致内存泄漏是因为 CHtmlView::Navigate 在这些函数中调用了两次,所以没有正确的释放资源 正因为有着这些MFC内部设计上的bug,所以才导致了1.17版的CHtmlView不能释放一些网络上的资源。 根据微软网站上的一些技术文章,我找到了解决办法,修改了CHtmlView,现在这个问题已经修复,重载上面的7个函数,并修改: CString CFixHtmlView::GetFullName() const { ASSERT(m_pBrowserApp != NULL); BSTR bstr; m_pBrowserApp->get_FullName(&bstr); CString retVal(bstr); SysFreeString(bstr); // Added this line to prevent leak. return retVal; } CString CFixHtmlView::GetType() const { ASSERT(m_pBrowserApp != NULL); BSTR bstr; m_pBrowserApp->get_Type(&bstr); CString retVal(bstr); SysFreeString(bstr); // Added this line to prevent leak. return retVal; } CString CFixHtmlView::GetLocationName() const { ASSERT(m_pBrowserApp != NULL); BSTR bstr; m_pBrowserApp->get_LocationName(&bstr); CString retVal(bstr); SysFreeString(bstr); // Added this line to prevent leak. return retVal; } CString CFixHtmlView::GetLocationURL() const { ASSERT(m_pBrowserApp != NULL); BSTR bstr; m_pBrowserApp->get_LocationURL(&bstr); CString retVal(bstr); SysFreeString(bstr); // Added this line to prevent leak. return retVal; } void CFixHtmlView::Navigate(LPCTSTR lpszURL, DWORD dwFlags /* = 0 */, LPCTSTR lpszTargetFrameName /* = NULL */ , LPCTSTR lpszHeaders /* = NULL */, LPVOID lpvPostData /* = NULL */, DWORD dwPostDataLen /* = 0 */) { CString strurl(/blog/lpszURL); BSTR bstrURL = strURL.AllocSysString(); COleSafeArray vPostData; if (lpvPostData != NULL) { if (dwPostDataLen == 0) dwPostDataLen = lstrlen((LPCTSTR) lpvPostData); vPostData.CreateOneDim(VT_UI1, dwPostDataLen, lpvPostData); } m_pBrowserApp->Navigate(bstrURL, COleVariant((long) dwFlags, VT_I4), COleVariant(lpszTargetFrameName, VT_BSTR), vPostData, COleVariant(lpszHeaders, VT_BSTR)); SysFreeString(bstrURL); // Added this line to prevent leak. } BOOL CFixHtmlView::LoadFromResource(LPCTSTR lpszResource) { HINSTANCE hInstance = AfxGetResourceHandle(); ASSERT(hInstance != NULL); CString strResourceURL; BOOL bRetVal = TRUE; LPTSTR lpszModule = new TCHAR[_MAX_PATH]; if (GetModuleFileName(hInstance, lpszModule, _MAX_PATH)) { strResourceURL.Format(_T("res://%s/%s"), lpszModule, lpszResource); Navigate(strResourceURL, 0, 0, 0); } else bRetVal = FALSE; delete [] lpszModule; return bRetVal; } BOOL CFixHtmlView::LoadFromResource(UINT nRes) { HINSTANCE hInstance = AfxGetResourceHandle(); ASSERT(hInstance != NULL); CString strResourceURL; BOOL bRetVal = TRUE; LPTSTR lpszModule = new TCHAR[_MAX_PATH]; if (GetModuleFileName(hInstance, lpszModule, _MAX_PATH)) { strResourceURL.Format(_T("res://%s/%d"), lpszModule, nRes); Navigate(strResourceURL, 0, 0, 0); } else bRetVal = FALSE; delete [] lpszModule; return bRetVal; } |