// 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 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 _NoAddRefOrRelease : public T { private: STDMETHOD_(ULONG, AddRef)() = 0; STDMETHOD_(ULONG, Release)() = 0; }; template 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* operator->() { return (_NoAddRefOrRelease*)m_ptr; } // coerce to underlying pointer type. operator T*() { return m_ptr; } // Templated version of QueryInterface template // 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; };