Некоторые вопросы об использовании CComPtr (при использовании Release ()? Могу ли я вернуть CComPtr ?,)

Я пишу надстройку для Internet Explorer (BHO) и использую интеллектуальные указатели CComPtr. Я думаю:

  1. Когда мне следует использовать функцию CComPtr.Release ()?

  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. Могу ли я безопасно вернуть CComPtr из функции?
  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. Я никогда не должен использовать обычный указатель?
  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?

person Mariusz Pawelski    schedule 26.11.2010    source источник
comment
+1 за использование ‹b› в разделе кода. Не знал этого.   -  person manuell    schedule 06.03.2014


Ответы (1)


К первому вопросу. 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», если вы не знаете, почему именно вы это делаете.

person sharptooth    schedule 26.11.2010
comment
Спасибо! 1 .: Я этого не знал. Вот почему в функции SetSite есть Release () (по ссылке в моем вопросе). Я подумал, что это будет умнее;) Значит, мне следует использовать Release, когда я использую один и тот же CComPtr не только для одного интерфейса? А когда я получаю объект с помощью оператора '&', да? Я имею в виду, что если я использую '=' и получаю ссылку от другого CComPtr, мне нужно вызывать Release? - person Mariusz Pawelski; 27.11.2010
comment
3 .: Я правильно понял ?: Когда я передаю CComPTR функции, которая принимает CComPtr, счетчик ссылок увеличивается в функциях, а затем уменьшается после возврата из функции. Затем программа выполняется в обычном режиме и делает то, что происходит после вызова. Вот почему мне не нужно передавать его как CComPtr, но я могу использовать обычный чистый указатель, потому что ничего не меняется. Но что, если функция вызывается асинхронно и после вызова функции вы освобождаете указатель (например, выходя за пределы области видимости)? - person Mariusz Pawelski; 27.11.2010
comment
@ CichyK24: если вы назначите другой указатель с помощью =, то объект, на который ранее указывался, будет освобожден - вы действительно можете войти в код ATL и посмотреть, как он работает. В Q3 - если функция вызывается асинхронно, вы должны хранить CComPtr где-нибудь, удерживая объект в живых, по крайней мере, на время этой функции - это может быть параметр функции или какая-то другая переменная. - person sharptooth; 29.11.2010