193 lines
3.8 KiB
C++
193 lines
3.8 KiB
C++
// SmartPtr.h
|
|
//
|
|
// Defines a smart pointer class that does not depend on any ATL headers
|
|
|
|
#pragma once
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Name: AreCOMObjectsEqual [template]
|
|
// Desc: Tests two COM pointers for equality.
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
template <class T1, class T2>
|
|
bool AreComObjectsEqual(T1 *p1, T2 *p2)
|
|
{
|
|
bool bResult = false;
|
|
if (p1 == NULL && p2 == NULL)
|
|
{
|
|
// Both are NULL
|
|
bResult = true;
|
|
}
|
|
else if (p1 == NULL || p2 == NULL)
|
|
{
|
|
// One is NULL and one is not
|
|
bResult = false;
|
|
}
|
|
else
|
|
{
|
|
// Both are not NULL. Compare IUnknowns.
|
|
IUnknown *pUnk1 = NULL;
|
|
IUnknown *pUnk2 = NULL;
|
|
if (SUCCEEDED(p1->QueryInterface(IID_IUnknown, (void**)&pUnk1)))
|
|
{
|
|
if (SUCCEEDED(p2->QueryInterface(IID_IUnknown, (void**)&pUnk2)))
|
|
{
|
|
bResult = (pUnk1 == pUnk2);
|
|
pUnk2->Release();
|
|
}
|
|
pUnk1->Release();
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
// _NoAddRefOrRelease:
|
|
// This is a version of our COM interface that dis-allows AddRef
|
|
// and Release. All ref-counting should be done by the SmartPtr
|
|
// object, so we want to dis-allow calling AddRef or Release
|
|
// directly. The operator-> returns a _NoAddRefOrRelease pointer
|
|
// instead of returning the raw COM pointer. (This behavior is the
|
|
// same as ATL's CComPtr class.)
|
|
template <class T>
|
|
class _NoAddRefOrRelease : public T
|
|
{
|
|
private:
|
|
STDMETHOD_(ULONG, AddRef)() = 0;
|
|
STDMETHOD_(ULONG, Release)() = 0;
|
|
};
|
|
|
|
template <class T>
|
|
class SmartPtr
|
|
{
|
|
public:
|
|
|
|
// Ctor
|
|
SmartPtr() : m_ptr(NULL)
|
|
{
|
|
}
|
|
|
|
// Ctor
|
|
SmartPtr(T *ptr)
|
|
{
|
|
m_ptr = ptr;
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
// Copy ctor
|
|
SmartPtr(const SmartPtr& sptr)
|
|
{
|
|
m_ptr = sptr.m_ptr;
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
// Dtor
|
|
~SmartPtr()
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->Release();
|
|
}
|
|
}
|
|
|
|
// Assignment
|
|
SmartPtr& operator=(const SmartPtr& sptr)
|
|
{
|
|
// Don't do anything if we are assigned to ourselves.
|
|
if (!AreComObjectsEqual(m_ptr, sptr.m_ptr))
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->Release();
|
|
}
|
|
|
|
m_ptr = sptr.m_ptr;
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->AddRef();
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// address-of operator
|
|
T** operator&()
|
|
{
|
|
return &m_ptr;
|
|
}
|
|
|
|
// dereference operator
|
|
_NoAddRefOrRelease<T>* operator->()
|
|
{
|
|
return (_NoAddRefOrRelease<T>*)m_ptr;
|
|
}
|
|
|
|
// coerce to underlying pointer type.
|
|
operator T*()
|
|
{
|
|
return m_ptr;
|
|
}
|
|
|
|
// Templated version of QueryInterface
|
|
|
|
template <class Q> // Q is another interface type
|
|
HRESULT QueryInterface(Q **ppQ)
|
|
{
|
|
return m_ptr->QueryInterface(__uuidof(Q), (void**)ppQ);
|
|
}
|
|
|
|
// safe Release() method
|
|
ULONG Release()
|
|
{
|
|
T *ptr = m_ptr;
|
|
ULONG result = 0;
|
|
if (ptr)
|
|
{
|
|
m_ptr = NULL;
|
|
result = ptr->Release();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Attach to an existing interface (does not AddRef)
|
|
void Attach(T* p)
|
|
{
|
|
if (m_ptr)
|
|
{
|
|
m_ptr->Release();
|
|
}
|
|
m_ptr = p;
|
|
}
|
|
|
|
|
|
|
|
// Detach the interface (does not Release)
|
|
T* Detach()
|
|
{
|
|
T* p = m_ptr;
|
|
m_ptr = NULL;
|
|
return p;
|
|
}
|
|
|
|
|
|
// equality operator
|
|
bool operator==(T *ptr) const
|
|
{
|
|
return AreComObjectsEqual(m_ptr, ptr);
|
|
}
|
|
|
|
// inequality operator
|
|
bool operator!=(T *ptr) const
|
|
{
|
|
return !operator==(ptr);
|
|
}
|
|
|
|
private:
|
|
T *m_ptr;
|
|
};
|