Chinaunix首页 | 论坛 | 博客
  • 博客访问: 642776
  • 博文数量: 133
  • 博客积分: 1566
  • 博客等级: 上尉
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-01 09:31
文章分类

全部博文(133)

文章存档

2019年(1)

2018年(1)

2017年(8)

2016年(9)

2015年(17)

2014年(4)

2013年(31)

2012年(25)

2011年(36)

2010年(1)

我的朋友

分类: 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 m_pProtocolSink;
CComPtr m_pBindInfo;

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    m_pProtocolSink;
CComPtr    m_pBindInfo;

变为
IInternetProtocolSink  *m_pProtocolSink;
IInternetBindInfo *m_pBindInfo;
 

 

 

阅读(1794) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~