11

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?
Mariusz Pawelski
  • 18,550
  • 7
  • 54
  • 71

1 Answers1

17

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.

Andrew Keeton
  • 18,949
  • 6
  • 40
  • 68
sharptooth
  • 159,303
  • 82
  • 478
  • 911
  • Thanks! 1.: I didn't know that. So that's why there is Release() in SetSite function(in the link in my question). I thought It would be smarter ;) So I should use Release when I'm using the same CComPtr more than just for one interface? And when I'm obtaining object by using '&' operator yes? I mean if I use '=' and get reference from other CComPtr do I have to call Release to? – Mariusz Pawelski Nov 27 '10 at 15:33
  • 3.: Do I get it right?: When I pass a CComPTR to function that accepts CComPtr the reference counter is increased in functions and then decreased after returning from function. Then program executes normally and do what's after the call. That's why I don't need to pass it as a CComPtr but can use normal pure pointer because nothing changes. But what if function is called asynchronously and after invoking function you release pointer (for example by going out of scope)? – Mariusz Pawelski Nov 27 '10 at 16:04
  • @CichyK24: If you assign another pointer with = the previously pointed to object will be released - you can actually step into ATL code and see how it works. To Q3 - if a function is called asynchronously you have to store a `CComPtr` somewhere holding the object alive for at least the duration of that function - it can be the function parameter or some other variable. – sharptooth Nov 29 '10 at 08:21