You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
5.8 KiB
319 lines
5.8 KiB
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
//
|
|
// Smart (Interface) pointer class
|
|
//
|
|
// 9-25-97 sburns
|
|
|
|
|
|
|
|
#ifndef SMARTPTR_HPP_INCLUDED
|
|
#define SMARTPTR_HPP_INCLUDED
|
|
|
|
|
|
|
|
namespace Burnslib
|
|
{
|
|
|
|
// Requires that T derive from IUnknown
|
|
|
|
template <class T>
|
|
class SmartInterface
|
|
{
|
|
public:
|
|
|
|
// need default ctor if we are to use STL containers to hold SmartInterfaces
|
|
|
|
SmartInterface()
|
|
:
|
|
|
|
#ifdef DBG
|
|
ptrGuard(0xDDDDDDDD),
|
|
#endif
|
|
|
|
ptr(0)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
explicit
|
|
SmartInterface(T* p)
|
|
|
|
#ifdef DBG
|
|
:
|
|
ptrGuard(0xDDDDDDDD)
|
|
#endif
|
|
|
|
{
|
|
// don't assert(p), since construction w/ 0 is legal.
|
|
|
|
ptr = p;
|
|
if (ptr)
|
|
{
|
|
ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SmartInterface(const SmartInterface<T>& s)
|
|
|
|
#ifdef DBG
|
|
:
|
|
ptrGuard(0xDDDDDDDD)
|
|
#endif
|
|
|
|
{
|
|
// makes no sense to pass null pointers
|
|
|
|
ASSERT(s.ptr);
|
|
ptr = s.ptr;
|
|
if (ptr)
|
|
{
|
|
ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
~SmartInterface()
|
|
{
|
|
Relinquish();
|
|
}
|
|
|
|
|
|
|
|
// Aquire means "take over from a dumb pointer, but don't AddRef it."
|
|
//
|
|
// This is used to take over ownership from a dumb pointer so that you
|
|
// don't have to remember to call Release on the dumb pointer.
|
|
//
|
|
// Example:
|
|
//
|
|
// SmartInterface<IFoo> smart(0);
|
|
// IFoo* dumb = 0;
|
|
//
|
|
// HRESULT hr =
|
|
// ::YourGetDumbPointerCall(
|
|
// __uuidof(IFoo),
|
|
// reinterpret_cast<void**>(&dumb));
|
|
// BREAK_ON_FAILED_HRESULT(hr);
|
|
//
|
|
// smart.Acquire(dumb);
|
|
//
|
|
// Don't call dumb->Release(), when smart dies it will release the
|
|
// pointer.
|
|
|
|
void
|
|
Acquire(T* p)
|
|
{
|
|
ASSERT(!ptr);
|
|
ptr = p;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
AcquireViaQueryInterface(IUnknown& i)
|
|
{
|
|
return AcquireViaQueryInterface(i, __uuidof(T));
|
|
}
|
|
|
|
|
|
|
|
// fallback for those interfaces that are not
|
|
// declared w/ __declspec(uuid())
|
|
|
|
HRESULT
|
|
AcquireViaQueryInterface(IUnknown& i, const IID& interfaceDesired)
|
|
{
|
|
ASSERT(!ptr);
|
|
HRESULT hr =
|
|
i.QueryInterface(interfaceDesired, reinterpret_cast<void**>(&ptr));
|
|
|
|
// don't assert success, since we might just be testing to see
|
|
// if an interface is available.
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
AcquireViaCreateInstance(
|
|
const CLSID& classID,
|
|
IUnknown* unknownOuter,
|
|
DWORD classExecutionContext)
|
|
{
|
|
return
|
|
AcquireViaCreateInstance(
|
|
classID,
|
|
unknownOuter,
|
|
classExecutionContext,
|
|
__uuidof(T));
|
|
}
|
|
|
|
|
|
|
|
// fallback for those interfaces that are not
|
|
// declared w/ __declspec(uuid())
|
|
|
|
HRESULT
|
|
AcquireViaCreateInstance(
|
|
const CLSID& classID,
|
|
IUnknown* unknownOuter,
|
|
DWORD classExecutionContext,
|
|
const IID& interfaceDesired)
|
|
{
|
|
ASSERT(!ptr);
|
|
|
|
HRESULT hr =
|
|
|
|
// REVIEWED-2002/02/18-sburns
|
|
// Callers of this function should make sure the flags do not allow for
|
|
// an out-of-proc create if the class only supports in-proc.
|
|
|
|
::CoCreateInstance(
|
|
classID,
|
|
unknownOuter,
|
|
classExecutionContext,
|
|
interfaceDesired,
|
|
reinterpret_cast<void**>(&ptr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
Relinquish()
|
|
{
|
|
if (ptr)
|
|
{
|
|
ptr->Release();
|
|
ptr = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
operator T*() const
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
// this allows SmartInterface instances to be passed as the first
|
|
// parameter to AquireViaQueryInterface. Note that this is a conversion
|
|
// to IUnknown&, not IUnknown*. An operator IUnknown* would be ambiguous
|
|
// with respect to operator T*.
|
|
//
|
|
// (does not return a const IUnknown&, as COM interfaces are not const
|
|
// aware.)
|
|
|
|
operator IUnknown&() const
|
|
{
|
|
ASSERT(ptr);
|
|
return *(static_cast<IUnknown*>(ptr));
|
|
}
|
|
|
|
|
|
|
|
// don't appear to need this: less is better.
|
|
// T&
|
|
// operator*()
|
|
// {
|
|
// ASSERT(ptr);
|
|
// return *ptr;
|
|
// }
|
|
|
|
|
|
|
|
T*
|
|
operator->() const
|
|
{
|
|
ASSERT(ptr);
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
T*
|
|
operator=(T* rhs)
|
|
{
|
|
ASSERT(rhs);
|
|
|
|
if (ptr != rhs)
|
|
{
|
|
Relinquish();
|
|
ptr = rhs;
|
|
if (ptr)
|
|
{
|
|
ptr->AddRef();
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
// This is required by some STL container classes.
|
|
|
|
const SmartInterface<T>&
|
|
operator=(const SmartInterface<T>& rhs)
|
|
{
|
|
this->operator=(rhs.ptr);
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
// // This might be a good idea, but std::list.erase chokes on it.
|
|
// ISSUE-2002/03/26-sburns maybe that's fixed w/ VS 7?
|
|
//
|
|
// T**
|
|
// operator& ()
|
|
// {
|
|
// ASSERT(!ptr);
|
|
//
|
|
// if (ptr)
|
|
// {
|
|
// return &ptr;
|
|
// }
|
|
// else
|
|
// {
|
|
// return 0;
|
|
// }
|
|
// }
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
// Some code that takes the address of an instance of this class is working
|
|
// by happy coincidence: that taking the address of an instance yields the
|
|
// same address as the ptr member. For chk builds, I am deliberately
|
|
// breaking that code by inserting a dummy guard value, so that &i != i.ptr
|
|
//
|
|
// You should not try to take the address of a SmartInterface in order to
|
|
// access the internal pointer. You should instead use one of the Acquire
|
|
// methods, or use a dumb pointer and then acquire it. Under no
|
|
// circumstances will we allow access to our internal state!
|
|
|
|
int ptrGuard;
|
|
#endif
|
|
|
|
T* ptr;
|
|
};
|
|
|
|
|
|
} // namespace Burnslib
|
|
|
|
|
|
|
|
#endif // SMARTPTR_HPP_INCLUDED
|
|
|