c++comsmart-pointersbho

Some questions about using CComPtr (when use Release()? Can I return CComPtr?, ...)


I writing add-on for Internet Explorer(BHO) and I'm using CComPtr smart pointers. I wonder:

  1. When should I use CComPtr.Release() function?

  2. In this this link it's used to release browser object. Where else should I use it? In 'normal' use (with my own classes) I don't need it. Should I use it in this situation:
    I get document object using 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;
            }
        }
    
    }
    
    Should I release spHTMLDocument in SetSite function like I do with m_spWebBrowser (like in link mentioned before)?
  3. Can I return CComPtr from a function safely?
  4. I mean like this:
    CComPtr getObjects(CComQIPtr<IHTMLDocument3> htmlDoc3)
    {
     CComPtr objects;
     hr = htmlDoc3->getElementsByTagName(CComBSTR(L"object"), &objects);
     if(SUCCEEDED(hr) && objects != NULL)
     {
      return objects;
     }
     return NULL;
    }
    
  5. Should I never use normal pointer?
  6. In previous link RemoveImages private function is declared this way:
    void RemoveImages(IHTMLDocument2 *pDocument); 
    but invoked with smart pointer:
    CComQIPtr<IHTMLDocument2> spHTMLDoc = spDispDoc;
    if (spHTMLDoc != NULL)
    {
     // Finally, remove the images.
     RemoveImages(spHTMLDoc);
    }
    
    I would rather write it this way:
    void RemoveImages(CComPtr<IHTMLDocument2> document2);
    Is it better?

Solution

  • To the first question. CComPtr::Release() has the same effect as assigning a null pointer to the object. You can call Release() (or assign a null pointer) if for whatever reason you want to release the object before the pointer goes out of scope. For example:

    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
    }
    

    You see, when GetObject() obtains the pointer it overwrites the value already stored in CComPtr. If CComPtr stores a non-null pointer it will just be overwritten (shallow copy) and the object pointed to by the original pointer will be leaked. You don't need Release() before the first GetObject() - the pointer is null at that point. And you don't need either after the second GetObject() - the object will be relased once the pointer goes out of scope.

    To the second question. Yes, you can return CComPtr but only if the caller also accepts it into CComPtr. The following code:

    ISomeInterface* pointer = YourFunctionReturningCComPtr();
    

    will not take ownership of the object, so the object will be released and pointer will become dangling. That's undefined behavior.

    To the third question CComPtr is for ownership. Usually there's no point in passing CComPtr as an "in" parameter unless you know why exactly you do it.