关于使用CComPtr的一些问题(当使用Release()时?我可以返回CComPtr吗?,...)

时间:2010-11-26 10:51:44

标签: c++ com smart-pointers bho

我为Internet Explorer(BHO)编写附加组件,我正在使用CComPtr智能指针。我想知道:

  1. 我应该何时使用CComPtr.Release()函数?

  2.  在此this链接中,它已用于发布 浏览器对象。我应该在哪里使用它?在'正常'使用(使用我自己的类)我不需要它。我应该在这种情况下使用它:
     我使用m_spWebBrowser-> get_Document(& spDispDoc)获取文档对象:    
    void STDMETHODCALLTYPE CHelloWorldBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
    {
        // Query for the IWebBrowser2 interface.
        CComQIPtr spTempWebBrowser = pDisp;
    
        // Is this event associated with the top-level browser?
        if (spTempWebBrowser && m_spWebBrowser &&
            m_spWebBrowser.IsEqualObject(spTempWebBrowser))
        {
            // Get the current document object from browser...
            CComPtr spDispDoc;
            hr = m_spWebBrowser->get_Document(&spDispDoc);
            if (SUCCEEDED(hr))
            {
                // ...and query for an HTML document.
                CComQIPtr htmlDoc2 = spDispDoc;
                m_spHTMLDocument = spHTMLDoc;
            }
        }
    
    }
    
     我应该像使用m_spWebBrowser一样在SetSite函数中释放spHTMLDocument(就像之前提到的链接一样)?
  3. 我可以安全地从函数返回CComPtr吗?
  4. 我的意思是这样的:
    CComPtr getObjects(CComQIPtr<IHTMLDocument3> htmlDoc3)
    {
     CComPtr objects;
     hr = htmlDoc3->getElementsByTagName(CComBSTR(L"object"), &objects);
     if(SUCCEEDED(hr) && objects != NULL)
     {
      return objects;
     }
     return NULL;
    }
    
  5. 我不应该使用普通指针吗?
  6. 在以前的链接中,RemoveImages私有函数以这种方式声明:
    void RemoveImages(IHTMLDocument2 *pDocument); 
    但是使用智能指针调用:
    CComQIPtr<IHTMLDocument2> spHTMLDoc = spDispDoc;
    if (spHTMLDoc != NULL)
    {
     // Finally, remove the images.
     RemoveImages(spHTMLDoc);
    }
    
    我宁愿这样写:
    void RemoveImages(CComPtr<IHTMLDocument2> document2);
    好点吗?

1 个答案:

答案 0 :(得分:17)

对第一个问题。 CComPtr::Release()与为对象分配空指针具有相同的效果。如果出于任何原因想要在指针超出范围之前释放对象,则可以调用Release()(或指定空指针)。例如:

CComPtr<ISomeInterface> pointer;
HRESULT hr = firstProvider->GetObject( &pointer );
if( SUCCEEDED( hr ) ) {
   //use the object
   pointer.Release();
}
HRESULT hr = secondProvider->GetObject( &pointer );
if( SUCCEEDED( hr ) ) {
   //use the object
}

您会看到,当GetObject()获取指针时,它会覆盖已存储在CComPtr中的值。如果CComPtr存储一个非空指针,它将被覆盖(浅拷贝),并且原始指针指向的对象将被泄露。在第一个Release()之前不需要GetObject() - 指针在该点为空。并且在第二个GetObject()之后你也不需要 - 一旦指针超出范围,对象就会被重新发送。

至第二个问题。是的,您可以返回CComPtr,但前提是调用者也接受CComPtr。以下代码:

ISomeInterface* pointer = YourFunctionReturningCComPtr();

不会取得对象的所有权,因此对象将被释放,pointer将变为悬空。这是未定义的行为。

对于第三个问题 CComPtr是为了所有权。通常没有必要将CComPtr作为“in”参数传递,除非您知道为什么要这样做。