ATL Internals 2ed複習.chapter 3.CComPtr CComQIPtr

A Review of Smart Pointers

使用smart pointers的好處:

對象析構時,自動release interface

發生異常時,創建在棧上的對象自動release interface

assignment操作時,舊的interface自動release,新的interface自動AddRef

提供不同的構造函數

可以在大部分用raw pointer的地方使用

 

ATL提供了2種smart pointer:

CComPtr<>

CComQIPtr<> //可以對不同類型的賦值對象做QueryInterface操作

 

The CComPtr and CComQIPtr Classes

template <class T>                                
class CComPtrBase {                               
    ...                                           
    T* p;                                         
};                                                
                                                  
template <class T>                                
class CComPtr : public CComPtrBase<T>             
{ ... };                                          
                                                  
template <class T, const IID* piid = &__uuidof(T)>
class CComQIPtr : public CComPtr<T>               
{ ... };                                          


T* p是其唯一的state

 

Constructors and Destructor

CComPtrBase()     { p = NULL; }                         
CComPtrBase(T* p) { if ((p = lp) != NULL) p->AddRef(); }
~CComPtrBase()    { if (p) p->Release(); }              
                                                        
CComPtr(const CComPtr<T>& lp) : CComPtrBase<T>(lp.p) { }
CComQIPtr(T* lp)  :                     
    CComPtr<T>(lp)                      
    {}                                  
                                        
CComQIPtr(const CComQIPtr<T,piid>& lp) :
    CComPtr<T>(lp.p)                    
    {}                                  

 

CComQIPtr(IUnknown* lp)                                        
    { if (lp != NULL) lp->QueryInterface(*piid, (void **)&p); }

當QueryInterface不成功時,應該注意到指針==null

void func (IUnknown* punk) {
    CComQIPtr<INamedObject> pno (punk);
    if (pno) {
        // Can call SomeMethod because the QI worked
        pno->SomeMethod ();
    }
}


Initialization

// CComPtr assignment operators                          
T* operator=(T* lp);                                     
template <typename Q> T* operator=(const CComPtr<Q>& lp);
T* operator=(const CComPtr<T>& lp);                      


 

// CComQIPtr assignment operators    
T* operator=(T* lp);                 
T* operator=(const CComQIPtr<T>& lp);
T* operator=(IUnknown* lp);          


注意CComQIPTR可以直接對非空interface pointer查詢

Object Instantiation Methods

HRESULT CoCreateInstance (REFCLSID rclsid,                  
                          LPUNKNOWN pUnkOuter = NULL,       
                          DWORD dwClsContext = CLSCTX_ALL) {
    ATLASSERT(p == NULL);                                   
    return ::CoCreateInstance(rclsid, pUnkOuter,            
        dwClsContext, __uuidof(T), (void**)&p);             
}                                                           
                                                            
HRESULT CoCreateInstance (LPCOLESTR szProgID,               
                          LPUNKNOWN pUnkOuter = NULL,       
                          DWORD dwClsContext = CLSCTX_ALL); 


例子:

ISpeaker* pSpeaker;
HRESULT hr =
 ::CoCreateInstance (__uuidof (Demagogue), NULL, CLSCTX_ALL,
                     __uuidof (ISpeaker_, (void**) &pSpeaker);
... Use the interface
pSpeaker->Release () ;


CComPtr<ISpeaker> pSpeaker;
HRESULT hr = pSpeaker.CoCreateInstance (__uuidof (Demogogue));
... Use the interface. It releases when pSpeaker leaves scope


 

CComPtr and CComQIPtr Operations

T& operator*() const { ATLENSURE(p!=NULL); return *p; }


 

T** operator&() { ATLASSERT(p==NULL); return &p; }


例子:

STDMETHODIMP SomeClass::UpdateObject (
    /* [in, out] */ IExpected** ppExpected);

CComPtr<IExpected> pE = /* Initialize to some value */ ;

pobj->UpdateObject (&pE); // Asserts in debug build because
                          // pE is non-NULL


也可以:

pobj->UpdateObject (&pE.p);


CComPtr and CComQIPtr Resource-Management Operations

注意如果smart pointer夾在CoInitilize()和CoUninitialize()之間,析構函數可能來不及運行

int main( ) {
    HRESULT hr = CoInitialize( NULL );
    If (FAILED(hr)) return 1;  // Something is seriously wrong

    CComPtr<IUnknown> punk = /* Initialize to some object */ ;
    ...
    punk.Release( ); // Must Release before CoUninitialize!

    CoUninitialize( );
}


上面這個例子使用點操作Release,所以操作之後內部指針=null;在ATL3之前如果使用->Release內部pointer將會釋放2次

void Release() {          
     T* pTemp = p;        
     if (pTemp) {         
         p = NULL;        
         pTemp->Release();
     }                    
}                         

ATL3之後,->操作AddRef和Release將會出現編譯錯誤:

_NoAddRefReleaseOnCComPtr<T>* operator->() const {              
    ATLASSERT(p!=NULL); return (_NoAddRefReleaseOnCComPtr<T>*)p;
}                                                               


template <class T>                         
class _NoAddRefReleaseOnCComPtr : public T {
    private:                               
        STDMETHOD_(ULONG, AddRef)()=0;     
        STDMETHOD_(ULONG, Release)()=0;    
};                                         

The CopyTo Method

HRESULT CopyTo(T** ppT) {             
    ATLASSERT(ppT != NULL);           
    if (ppT == NULL) return E_POINTER;
    *ppT = p;                         
    if (p) p->AddRef();               
    return S_OK;                      
}                                     


通常,使用CopyTo來製造[out]:

STDMETHODIMP SomeClass::get_Object(
/* [out] */ IExpected** ppExpected) {
    // Interface saved in member m_object
    // of type CComPtr<IExpected>

    // Correctly AddRefs pointer
    return m_object.CopyTo (ppExpected) ;
}


注意下面的錯誤代碼:

STDMETHODIMP SomeClass::get_Object (
/* [out] */ IExpected** ppExpected) {
    // Interface saved in member m_object
    // of type CComPtr<IExpected>
    *ppExpected = m_object ;  // Wrong! Does not AddRef pointer!
}


The Type-Cast Operator

operator T*() const { return (T*) p; }


例子:

STDMETHODIMP SomeClass::put_Object (
    /* [in] */ IExpected* pExpected);

// Interface saved in member m_object of type CComPtr<IExpected>
// Correctly does not AddRef pointer!
pObj->put_Object (m_object) ;


The Detach and Attach Methods

T* Detach() { T* pt = p; p = NULL; return pt; }


例子:

STDMETHODIMP SomeClass::get_Object (
/* [out] */ IExpected** ppExpected) {
  CComPtr<IExpected> pobj = /* Initialize the smart pointer */ ;
  *ppExpected = pobj->Detach(); // Destructor no longer Releases
  return S_OK;
}


上述可以避免不必要的AddRef/Release操作

 

void Attach(T* p2) { if (p) p->Release(); p = p2; }

例子:

STDMETHODIMP SomeClass::get_Object (
  /* [out] */ IExpected** ppObject);

void VerboseGetOption () {
  IExpected* p;
  pObj->get_Object (&p) ;

  CComPtr<IExpected> pE;
  pE.Attach (p); // Destructor now releases the interface pointer
  // Let the exceptions fall where they may now!!!
  CallSomeFunctionWhichThrowsExceptions();
}

 

Miscellaneous Smart Pointer Methods

template <class Q>                                    
HRESULT QueryInterface(Q** pp) const {                
    ATLASSERT(pp != NULL && *pp == NULL);             
    return p->QueryInterface(__uuidof(Q), (void**)pp);
}                                                     


例子:

CComPtr<IFoo> pfoo = /* Initialize to some IFoo */
IBar* pbar;

// We specify an IBar variable so the method queries for IID_IBar
HRESULT hr = pfoo.QueryInterface(&pBar);


 

bool IsEqualObject(IUnknown* pOther);


例子:

bool SameObjects(IUnknown* punk1, IUnknown* punk2) {
    CComPtr<IUnknown> p (punk1);
    return p.IsEqualObject (punk2);
}

IUnknown* punk1 = NULL;
IUnknown* punk2 = NULL;
ATLASSERT (SameObjects(punk1, punk2); // true


 

HRESULT SetSite(IUnknown* punkParent);


 

HRESULT Advise(IUnknown* pUnk, const IID& iid, LPDWORD pdw);
                                                            
CComPtr<ISource> ps /* Initialized via some mechanism */ ;
ISomeSink* psink = /* Initialized via some mechanism */ ;
DWORD dwCookie;

ps->Advise (psink, __uuidof(ISomeSink), &dwCookie);


CComPtr Comparison Operators

bool operator!() const       { return (p == NULL); }   
bool operator< (T* pT) const { return p <  pT; }       
bool operator==(T* pT) const { return p == pT; }       
bool operator!=(T* pT) const { return !operator==(pT); }

The CComPtr Specialization for IDispatch

//specialization for IDispatch                            
template <>                                               
class CComPtr<IDispatch> : public CComPtrBase<IDispatch> {
public:                                                   
    CComPtr() {}                                          
    CComPtr(IDispatch* lp)  :                             
        CComPtrBase<IDispatch>(lp) {}                     
    CComPtr(const CComPtr<IDispatch>& lp) :               
        CComPtrBase<IDispatch>(lp.p) {}                   
};                                                        

Property Accessor and Mutator Methods

HRESULT GetIDOfName(LPCOLESTR lpsz, DISPID* pdispid);

 

HRESULT GetProperty(DISPID dwDispID, VARIANT* pVar);
HRESULT PutProperty(DISPID dwDispID, VARIANT* pVar);


上述兩步可以合併:

HRESULT GetPropertyByName(LPCOLESTR lpsz, VARIANT* pVar);
HRESULT PutPropertyByName(LPCOLESTR lpsz, VARIANT* pVar);


 

Method Invocation Helper Functions

HRESULT Invoke0(DISPID dispid, VARIANT* pvarRet = NULL);     
HRESULT Invoke0(LPCOLESTR lpszName, VARIANT* pvarRet = NULL);
HRESULT Invoke1(DISPID dispid, VARIANT* pvarParam1,          
    VARIANT* pvarRet = NULL);                                
HRESULT Invoke1(LPCOLESTR lpszName,                          
        VARIANT* pvarParam1, VARIANT* pvarRet = NULL);       
HRESULT Invoke2(DISPID dispid,                               
        VARIANT* pvarParam1, VARIANT* pvarParam2,            
        VARIANT* pvarRet = NULL);                            
HRESULT Invoke2(LPCOLESTR lpszName,                          
        VARIANT* pvarParam1, VARIANT* pvarParam2,            
        VARIANT* pvarRet = NULL);                            
HRESULT InvokeN(DISPID dispid,                               
        VARIANT* pvarParams, int nParams,                    
        VARIANT* pvarRet = NULL);                            
HRESULT InvokeN(LPCOLESTR lpszName,                          
        VARIANT* pvarParams, int nParams,                    
        VARIANT* pvarRet = NULL);                            


注意使用數組傳遞參數時,應該倒敘

 

例子:

HRESULT TheEasyWay( IDispatch *spCalcDisp ) {
  CComPtr< IDispatch > spCalcDisp( pCalcDisp );

  CComVariant varOp1( 6.0 );
  CComVariant varOp2( 7.0 );
  CComVariant varResult;
  HRESULT hr = spCalcDisp.Invoke2( OLESTR( "Add" ),
    &varOp1, &varOp2, &varResult );
  // varResult now holds sum of 6 and 7
}


 

static HRESULT GetProperty(IDispatch* pDisp, DISPID dwDispID,
    VARIANT* pVar);                                          
static HRESULT PutProperty(IDispatch* pDisp, DISPID dwDispID,
    VARIANT* pVar);                                          


例子:

HRESULT GetCount(IDispatch* pdisp, long* pCount) {
    *pCount = 0;
    const int DISPID_COUNT = 1;

    CComVariant v;
    CComPtr<IDispatch>::GetProperty (pdisp, DISPID_COUNT, &v);

    HRESULT hr = v.ChangeType (VT_I4);
    If (SUCCEEDED (hr))
        *pCount = V_I4(&v) ;
    return hr;
}

 

 

 


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章