分类: Windows平台
2013-05-29 10:54:29
1. 无法退出的现象
当关闭MFC SDI程序窗口时,会执行下面的一段代码
/////////////////////////////////////////////////////////////////////////////
// CFrameWnd closing down
void CFrameWnd::OnClose()
{
if (m_lpfnCloseProc != NULL)
(*m_lpfnCloseProc)(this);
// Note: only queries the active document
CDocument* pDocument = GetActiveDocument();
if (pDocument != NULL && !pDocument->CanCloseFrame(this))
{
// document can't close right now -- don't close it
return;
}
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->m_pMainWnd == this)
{
// attempt to save all documents
if (pDocument == NULL && !pApp->SaveAllModified())
return; // don't close it
// hide the application's windows before closing all the documents
pApp->HideApplication();
// close all documents first
pApp->CloseAllDocuments(FALSE);
// don't exit if there are outstanding component objects
if (!AfxOleCanExitApp())
{
// take user out of control of the app
AfxOleSetUserCtrl(FALSE);
// don't destroy the main window and close down just yet
// (there are outstanding component (OLE) objects)
return;
}
// there are cases where destroying the documents may destroy the
// main window of the application.
if (!afxContextIsDLL && pApp->m_pMainWnd == NULL)
{
AfxPostQuitMessage(0);
return;
}
}
// detect the case that this is the last frame on the document and
// shut down with OnCloseDocument instead.
if (pDocument != NULL && pDocument->m_bAutoDelete)
{
BOOL bOtherFrame = FALSE;
POSITION pos = pDocument->GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = pDocument->GetNextView(pos);
ENSURE_VALID(pView);
if (pView->GetParentFrame() != this)
{
bOtherFrame = TRUE;
break;
}
}
if (!bOtherFrame)
{
pDocument->OnCloseDocument();
return;
}
// allow the document to cleanup before the window is destroyed
pDocument->PreCloseFrame(this);
}
// then destroy the window
DestroyWindow();
}
在执行到代码30行处时,执行函数AfxOleCanExitApp以确定当前Ole是否能够退出
BOOL AFXAPI AfxOleCanExitApp()
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
return pModuleState->m_nObjectCount == 0;
}
pModuleState->m_nObjectCount == 0表示如果COM组件中的实例对象为零,则Ole能够退出
2 问题点
根据上述思路,在自定义异步可插入协议的实现中,发现CComPtr定义的变量使用过程中出现问题
utHttp.h
CComPtr
CComPtr
utHttp.cpp
m_pProtocolSink = pOIProtSink;
m_pBindInfo = pOIBindInfo;
依照 COM 指针的引用时计数的原则,CComPtr 在实现的时候实现了自动化的引用计数。即在任何 "=" 操作的时候 AddRef,而在无效时 Release。我们来看看 "=" 运算符的具体实现代码是什么样的:
从这段代码可以知道,CComPtr 在拿到指针后,并不是直接将其保存到自己的指针里面,而是先对拿到的指针进行 AddRef,保证引用计数,而后才执行 *pp = lp。
根据上述描述
m_pProtocolSink = pOIProtSink;
m_pBindInfo = pOIBindInfo;
在执行上面两行时,COM对象pOIProtSink/pOIBindInfo都会首先执行
pOIProtSink->AddRef()
pOIBindInfo->AddRef()
但没有执行
pOIProtSink->Release()
pOIBindInfo->Release()
造成的结果是,在程序退出过程中执行AfxOleCanExitApp函数时,发现有COM对象没有释放,导致退出操作失败
m_pProtocolSink = pOIProtSink;
m_pBindInfo = pOIBindInfo;
将上述赋值语句进行修改
3 修改
1) 方法一
m_pProtocolSink = pOIProtSink;
m_pBindInfo = pOIBindInfo;
pOIProtSink->Release();
pOIBindInfo->Release();
2)方法二
m_pProtocolSink.Attach(pOIProtSink);
m_pBindInfo.Attach(pOIBindInfo);
3)方法三
将下面声明
CComPtr
CComPtr
变为
IInternetProtocolSink *m_pProtocolSink;
IInternetBindInfo *m_pBindInfo;