I writing add-on for Internet Explorer(BHO) and I'm using CComPtr smart pointers. I wonder:
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)?
CComPtr getObjects(CComQIPtr<IHTMLDocument3> htmlDoc3) { CComPtr objects; hr = htmlDoc3->getElementsByTagName(CComBSTR(L"object"), &objects); if(SUCCEEDED(hr) && objects != NULL) { return objects; } return NULL; }
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?
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.