您的位置:首页 > 其它

ATL Internals 2ed复习.chapter 3.CComPtr CComQIPtr

2012-10-01 21:55 399 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: