#pragma once
/*! \mainpage
*
* \section License
*
* Copyright (c) 2011, KO Software (official@ko-sw.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - All original and modified versions of this source code must include the
* above copyright notice, this list of conditions and the following
* disclaimer.
*
* - The name of KO Software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY KO SOFTWARE ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT WILL KO SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <utility>
////////////////////////////////////////////////////////////////////////////////
//! \def SUPPORTED_CPP0X
//! When set to nonzero, C++0X code with variadic templates will be present.
#ifdef __GXX_EXPERIMENTAL_CXX0X__
# define SUPPORTED_CPP0X 1
#else
# define SUPPORTED_CPP0X 0
#endif //__GXX_EXPERIMENTAL_CXX0X__
////////////////////////////////////////////////////////////////////////////////
//! \def SUPPORTED_UUIDOF
//! When set to nonzero, assumes that the compiler can provide a built-in
//! __uuidof operator.
#ifdef _MSC_EXTENSIONS
# define SUPPORTED_UUIDOF 1
#else
# define SUPPORTED_UUIDOF 0
#endif //_MSC_EXTENSIONS
////////////////////////////////////////////////////////////////////////////////
#if (SUPPORTED_UUIDOF == 0)
template<typename t>
struct hold_uuidof { static GUID __IID; };
# define DECLSPEC_NOVTABLE
# define DEFINE_UUIDOF_ID(Q, IID) template<> GUID hold_uuidof<Q>::__IID = IID;
# define DEFINE_UUIDOF(Q) DEFINE_UUIDOF_ID(Q, IID_##Q)
# define __uuidof(Q) hold_uuidof<Q>::__IID
#endif // (SUPPORTED_UUIDOF != 0)
//! \brief
//! Provides discovery information for a supported COM interface.
//!
//! \tparam tInterface The type of the interface being discovered.
//!
//! \tparam tIID The interface ID of \a tInterface.
template<typename tInterface, LPCGUID tIID = &__uuidof(tInterface)>
class DECLSPEC_NOVTABLE ComEntryDiscoverable
{
public:
typedef tInterface Interface;
public:
//! \brief
//! Represents the main method for interface discovery infrastructure.
//!
//! \remarks
//! This method is called internally by the ComInstance class when its
//! QueryInterface method is invoked.
template<typename tObject>
static HRESULT InternalQueryInterface(REFIID theIID, tObject * theObj, void ** theOut)
{
if (theIID == *tIID)
*theOut = static_cast<tInterface *>(theObj);
else
return E_NOINTERFACE;
return S_OK;
}
};
//! \brief
//! Implements exactly one COM interface and provides discovery
// information for it.
template<typename tInterface, LPCGUID tIID = &__uuidof(tInterface)>
class DECLSPEC_NOVTABLE ComEntry : public tInterface, public ComEntryDiscoverable<tInterface, tIID>
{ };
//! \brief
//! Provides discovery information for a parent COM interface that is common
//! between two or more child COM interfaces being implemented.
//!
//! \tparam tInterface The type of the interface being discovered.
//!
//! \tparam tIntermediate The interface that is a child of \a tInterface that
//! can serve as a hint for resolving casting ambiguities.
//!
//! \tparam tIID The interface ID of \a tInterface.
//!
//! \remarks
//! This class is necessary for providing discovery information about IUnknown
//! since the latter is parent for all COM interfaces. In such cases where direct
//! cast to IUnknown is not possible, two-step casting is necessary.
template<typename tInterface, typename tIntermediate, LPCGUID tIID = &__uuidof(tInterface)>
class DECLSPEC_NOVTABLE ComEntry2StepDiscoverable
{
public:
typedef tInterface Interface;
protected:
template<typename tObject>
static HRESULT InternalQueryInterface(REFIID theIID, tObject * theObj, void ** theOut)
{
if (theIID == *tIID)
*theOut = static_cast<tInterface *>( static_cast<tIntermediate *>(theObj) );
else
return E_NOINTERFACE;
return S_OK;
}
};
//! \brief
//! Represents a terminating block for interface discovery, allowing for
//! discovery of IUnknown.
//!
//! \tparam tIntermediate Any interface that implements IUnknown.
template <typename tIntermediate>
class DECLSPEC_NOVTABLE ComEntryTerminator :
public ComEntry2StepDiscoverable<IUnknown, tIntermediate>
{ };
//! \brief
//! Represents a compound COM entry that can implement n COM interfaces and
//! contain discovery information about (n+1) COM interfaces where the last interface
//! must always be IUnknown.
//!
//! \tparam tEntry1 The first COM entry.
//! \tparam tEntry2 Second COM entry. If unneeded, a terminating entry
//! is used, providing discovery of IUnknown.
//! \remarks
//! In order to implement more than one COM interface,
//! this class can be daisy-chained in the \a tEntry2 template argument.
template <typename tEntry1, typename tEntry2 = ComEntryTerminator<typename tEntry1::Interface> >
class DECLSPEC_NOVTABLE ComEntryCompound : public tEntry1, public tEntry2
{
public:
template<typename tObject>
static HRESULT InternalQueryInterface(REFIID theIID, tObject * theObj, void ** theOut)
{
HRESULT aRes = tEntry1::InternalQueryInterface(theIID, theObj, theOut);
if ( FAILED(aRes) )
aRes = tEntry2::InternalQueryInterface(theIID, theObj, theOut);
return aRes;
}
};
////////////////////////////////////////////////////////////////////////////////
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus IUnknown.
//!
//! \tparam tInterface1 The interface being implemented.
template <typename tInterface1>
class DECLSPEC_NOVTABLE ComEntry1 :
public ComEntryCompound
<
ComEntry<tInterface1>
>
{ };
//! \brief
//! Implements exactly two COM interfaces and provides discovery information
//! about these interfaces, plus IUnknown.
//!
//! \tparam tInterface1 The first interface being implemented.
//!
//! \tparam tInterface2 The second interface being implemented.
template <typename tInterface1, typename tInterface2>
class DECLSPEC_NOVTABLE ComEntry2 :
public ComEntryCompound
<
ComEntry<tInterface1>,
ComEntry1<tInterface2>
>
{ };
//! \brief
//! Implements exactly three COM interfaces and provides discovery information
//! about these interfaces, plus IUnknown.
//!
//! \tparam tInterface1 The first interface being implemented.
//!
//! \tparam tInterface2 The second interface being implemented.
//!
//! \tparam tInterface3 The third interface being implemented.
template <typename tInterface1, typename tInterface2, typename tInterface3>
class DECLSPEC_NOVTABLE ComEntry3 :
public ComEntryCompound
<
ComEntry<tInterface1>,
ComEntry2<tInterface2, tInterface3>
>
{ };
//! \brief
//! Implements exactly four COM interfaces and provides discovery information
//! about these interfaces, plus IUnknown.
//!
//! \tparam tInterface1 The first interface being implemented.
//!
//! \tparam tInterface2 The second interface being implemented.
//!
//! \tparam tInterface3 The third interface being implemented.
//!
//! \tparam tInterface4 The fourth interface being implemented.
template <typename tInterface1, typename tInterface2, typename tInterface3, typename tInterface4>
class DECLSPEC_NOVTABLE ComEntry4 :
public ComEntryCompound
<
ComEntry<tInterface1>,
ComEntry3<tInterface2, tInterface3, tInterface4>
>
{ };
//! \brief
//! Implements exactly five COM interfaces and provides discovery information
//! about these interfaces, plus IUnknown.
//!
//! \tparam tInterface1 The first interface being implemented.
//!
//! \tparam tInterface2 The second interface being implemented.
//!
//! \tparam tInterface3 The third interface being implemented.
//!
//! \tparam tInterface4 The fourth interface being implemented.
//!
//! \tparam tInterface5 The fifth interface being implemented.
template <typename tInterface1, typename tInterface2, typename tInterface3, typename tInterface4, typename tInterface5>
class DECLSPEC_NOVTABLE ComEntry5 :
public ComEntryCompound
<
ComEntry<tInterface1>,
ComEntry4<tInterface2, tInterface3, tInterface4, tInterface5>
>
{ };
////////////////////////////////////////////////////////////////////////////////
// Variadic-template versions
#if (SUPPORTED_CPP0X != 0)
//! \brief
//! Implements an arbitrary number of COM interfaces and provides discovery
//! information about these interfaces, plus IUnknown.
//!
//! \tparam tInterfaces The list of interfaces being implemented.
template<typename ... tInterfaces>
class DECLSPEC_NOVTABLE ComEntryV;
template<typename tInterface, typename ... tTail>
class DECLSPEC_NOVTABLE ComEntryV<tInterface, tTail...> :
public ComEntryCompound
<
ComEntry<tInterface>,
ComEntryV<tTail...>
>
{ };
template <typename tInterface>
class DECLSPEC_NOVTABLE ComEntryV<tInterface> :
public ComEntry1<tInterface>
{ };
#endif //(SUPPORTED_CPP0X != 0)
////////////////////////////////////////////////////////////////////////////////
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus an additional interface which the implemented
//! interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParent The parent class that \a tInterface derives from.
template<typename tInterface, typename tParent>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscovery1 :
public tInterface,
public ComEntryCompound
<
ComEntryDiscoverable<tInterface>,
ComEntry2StepDiscoverable<tParent, tInterface>
>
{
public:
typedef tInterface Interface;
};
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus two additional interfaces which the implemented
//! interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParent1 The first parent class that \a tInterface derives from.
//!
//! \tparam tParent2 The second parent class that \a tInterface derives from.
template<typename tInterface, typename tParent1, typename tParent2>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscovery2 :
public ComEntryCompound
<
ComEntry2StepDiscoverable<tParent1, tInterface>,
ComEntryWithParentDiscovery1<tInterface, tParent2>
>
{
public:
typedef tInterface Interface;
};
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus three additional interfaces which the implemented
//! interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParent1 The first parent class that \a tInterface derives from.
//!
//! \tparam tParent2 The second parent class that \a tInterface derives from.
//!
//! \tparam tParent3 The third parent class that \a tInterface derives from.
template<typename tInterface, typename tParent1, typename tParent2, typename tParent3>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscovery3 :
public ComEntryCompound
<
ComEntry2StepDiscoverable<tParent1, tInterface>,
ComEntryWithParentDiscovery2<tInterface, tParent2, tParent3>
>
{
public:
typedef tInterface Interface;
};
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus four additional interfaces which the implemented
//! interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParent1 The first parent class that \a tInterface derives from.
//!
//! \tparam tParent2 The second parent class that \a tInterface derives from.
//!
//! \tparam tParent3 The third parent class that \a tInterface derives from.
//!
//! \tparam tParent4 The fourth parent class that \a tInterface derives from.
template<typename tInterface, typename tParent1, typename tParent2, typename tParent3, typename tParent4>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscovery4 :
public ComEntryCompound
<
ComEntry2StepDiscoverable<tParent1, tInterface>,
ComEntryWithParentDiscovery3<tInterface, tParent2, tParent3, tParent4>
>
{
public:
typedef tInterface Interface;
};
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus file additional interfaces which the implemented
//! interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParent1 The first parent class that \a tInterface derives from.
//!
//! \tparam tParent2 The second parent class that \a tInterface derives from.
//!
//! \tparam tParent3 The third parent class that \a tInterface derives from.
//!
//! \tparam tParent4 The fourth parent class that \a tInterface derives from.
//!
//! \tparam tParent5 The fifth parent class that \a tInterface derives from.
template<typename tInterface, typename tParent1, typename tParent2, typename tParent3, typename tParent4, typename tParent5>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscovery5 :
public ComEntryCompound
<
ComEntry2StepDiscoverable<tParent1, tInterface>,
ComEntryWithParentDiscovery4<tInterface, tParent2, tParent3, tParent4, tParent5>
>
{
public:
typedef tInterface Interface;
};
////////////////////////////////////////////////////////////////////////////////
// Variadic-template versions
#if (SUPPORTED_CPP0X != 0)
//! \brief
//! Implements exactly one COM interface and provides discovery information
//! about this interface, plus an arbitrary number of interfaces which the
//! implemented interface derives from.
//!
//! \tparam tInterface The interface being implemented.
//!
//! \tparam tParents The variable-length list of parent class that
//! \a tInterface derives from.
template <typename tChild, typename ... tParents>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscoveryV;
template <typename tChild, typename tParent, typename ... tTail>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscoveryV<tChild, tParent, tTail...> :
public ComEntryCompound
<
ComEntry2StepDiscoverable<tParent, tChild>,
ComEntryWithParentDiscoveryV<tChild, tTail...>
>
{
public:
typedef tChild Interface;
};
template <typename tChild, typename tParent>
class DECLSPEC_NOVTABLE ComEntryWithParentDiscoveryV<tChild, tParent> :
public ComEntryWithParentDiscovery1<tChild, tParent>
{ };
#endif //(SUPPORTED_CPP0X != 0)
////////////////////////////////////////////////////////////////////////////////
//! \brief
//! Stores the number of references to a COM object instance.
//!
//! \tparam tThreadSafe If true, increment/decrement operations are implemented
//! via interlocking. This allows for class utilization in
//! a free threaded environment.
//!
//! \see ComInstance
template<bool tThreadSafe = false>
struct ComRefCount
{
LONG myNumRefs;
//! Creates a default instance of the COM reference counter.
//!
//! \remarks
//! The number of references is set to one because the entity in which
//! the object is created implicitly holds one reference to the object.
ComRefCount() : myNumRefs(1L) { }
//! Increments the reference counter based on the threading model
//! specified in the \a tThreadSafe template argument.
ULONG STDMETHODCALLTYPE AddRef()
{
if (!tThreadSafe)
return ++myNumRefs;
else
return InterlockedIncrement(&myNumRefs);
}
//! \brief
//! Decrements the reference counter based on the threading model
//! specified in the \a tThreadSafe template argument. If the reference
//! counter becomes non-positive, deletes the object.
//!
//! \tparam tObj The type of the object that may be deleted.
//!
//! \param theObj The pointer to the object that may be deleted if the
//! reference counter becomes non-positive.
//!
//! Because this method uses templates, the object class does not have to
//! have a virtual destructor to perform its deletion.
template<typename tObj>
ULONG STDMETHODCALLTYPE Release(tObj * theObj)
{
ULONG aNumRefs;
if (!tThreadSafe)
aNumRefs = --myNumRefs;
else
aNumRefs = InterlockedDecrement(&myNumRefs);
if (aNumRefs <= 0L)
delete theObj;
return aNumRefs;
}
};
////////////////////////////////////////////////////////////////////////////////
//! \brief
//! Represents an instance of a COM object and provides top-level implementation
//! of the IUnknown reference.
//!
//! \tparam tImpl
//! The type of the class that provides the actual functionality.
//! The class is that is must always have the following interface discovery
//! static member function:
//! \code
//! template<typename tObject>
//! static HRESULT InternalQueryInterface(REFIID, tObject *, void **);
//! \endcode
//! Typically tImpl derives from one of the ComEntry* specialization
//! based on the interfaces that the class implements.
//!
//!
//! \tparam tThreadSafe
//! If true, increment/decrement operations of the COM reference
//! counter are implemented via interlocking. This allows for class
//! creating free threaded objects.
template<typename tImpl, bool tThreadSafe = false>
class ComInstance : public tImpl
{
protected:
ComRefCount<tThreadSafe> myRefs;
public:
ComInstance()
{ }
#if (SUPPORTED_CPP0X != 0)
template<typename ... tParams>
ComInstance(tParams && ... theParams)
: tImpl( std::forward<tParams>(theParams)... )
{ }
#else
template<typename tParam1>
ComInstance(tParam1 theParam1)
: tImpl(theParam1)
{ }
template<typename tParam1, typename tParam2>
ComInstance(tParam1 theParam1, tParam2 theParam2)
: tImpl(theParam1, theParam2)
{ }
template<typename tParam1, typename tParam2, typename tParam3>
ComInstance(tParam1 theParam1, tParam2 theParam2, tParam3 theParam3)
: tImpl(theParam1, theParam2, theParam3)
{ }
template<typename tParam1, typename tParam2, typename tParam3, typename tParam4>
ComInstance(tParam1 theParam1, tParam2 theParam2, tParam3 theParam3, tParam4 theParam4)
: tImpl(theParam1, theParam2, theParam3, theParam4)
{ }
template<typename tParam1, typename tParam2, typename tParam3, typename tParam4, typename tParam5>
ComInstance(tParam1 theParam1, tParam2 theParam2, tParam3 theParam3, tParam4 theParam4, tParam5 theParam5)
: tImpl(theParam1, theParam2, theParam3, theParam4, theParam5)
{ }
#endif // (SUPPORTED_CPP0X != 0)
public:
//! \brief Top-level implementation of IUnknown::AddRef.
ULONG STDMETHODCALLTYPE AddRef()
{
return myRefs.AddRef();
}
//! \brief Top-level implementation of IUnknown::Release.
ULONG STDMETHODCALLTYPE Release()
{
return myRefs.Release(this);
}
//! \brief Top-level implementation of IUnknown::QueryInterface.
//!
//! \remarks
//! This method implies that the implementation class provides
//! interface discovery information via the \a InternalQueryInterface
//! static member function.
STDMETHODIMP QueryInterface(REFIID theIID, void ** theOut)
{
HRESULT aRes = tImpl::InternalQueryInterface(theIID, this, theOut);
if ( SUCCEEDED(aRes) )
AddRef();
return aRes;
}
};