//**************************************************************************************************
//
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//
// "COM"-CLASSES (IN-HEADER IMPLEMENTATION):
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma once
#ifndef COMMON_HELPERS_H
   #error "This header file requires 'CommonHelpers.h' to be priory included."
#endif
#define HCOM_H

#include <WinBase.h>
#ifndef __unknwn_h__
   #include <Unknwn.h>
#endif // __unknwn_h__

namespace CommonHelpers {

//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//
// "IUnknown" HELPERS:
//
//==================================================================================================
ref class HTCOMInterface { HTCOMInterface(){} public:
//--------------------------------------------------------------------------------------------------

static bool Release($PIUNKNOWN pIUnknown)
{
   return HUnsafeCOMInterface::Release( pIUnknown );
}

static bool Release(... array<$PIUNKNOWN>^ pointersToIUnknown)
{
   HArgChecking::VerifyNotNull( pointersToIUnknown );
   bool result = false;
   for ( int i = pointersToIUnknown -> GetLowerBound(0);
             i <= pointersToIUnknown -> GetUpperBound(0);
             i++ )
      if ( Release( pointersToIUnknown[ i ] ) )
         result = true;
   return result;
}

//--------------------------------------------------------------------------------------------------

template<typename TIUnknown> static bool ResetAndRelease($OPT TIUnknown*% pIUnknown)
{
   return HUnsafeCOMInterface::Release( HTPointer::NullValueExchange( pIUnknown ) );
}

static bool ResetAndRelease($PPIUNKNOWN pPIUnknown)
{
   return HUnsafeCOMInterface::ResetAndRelease( ($PPVOID)pPIUnknown );
}

static bool ResetAndRelease(... array<$PPIUNKNOWN>^ pointersToPIUnknown)
{
   HArgChecking::VerifyNotNull( pointersToPIUnknown );
   bool result = false;
   for ( int i = pointersToPIUnknown -> GetLowerBound(0);
             i <= pointersToPIUnknown -> GetUpperBound(0);
             i++ )
   {
      $PPIUNKNOWN volatile pPIUnknown = pointersToPIUnknown[ i ];
      result = result || ResetAndRelease( pPIUnknown );
   }
   return result;
}

//--------------------------------------------------------------------------------------------------
}; // HTCOMInterface
//==================================================================================================


//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//
// COM DUMMY OBJECT:
//
//==================================================================================================
class HTCOMDummyObject: public IUnknown {
//--------------------------------------------------------------------------------------------------
public:
   HTCOMDummyObject()
   {
      ::InterlockedExchange( &_RefCount_, 1 );
   }

// === IUnknown methods: ===

   STDMETHODIMP_($UINT) AddRef()
   {
      return ::InterlockedIncrement( &_RefCount_ );
   }

   STDMETHODIMP_($UINT) Release()
   {
      $UINT refCount = ::InterlockedDecrement( &_RefCount_ );
      if ( !refCount )
         delete this;
      return refCount;
   }

   STDMETHODIMP QueryInterface( REFIID riid, $PPVOID ppvObject )
   {
      HUnsafePtrArgChecking::VerifyNotNull( ppvObject );
      if ( ::IsEqualIID( riid, IID_IPersist ) ||
           ::IsEqualIID( riid, IID_IUnknown ) )
      {
         AddRef();
         HUnsafePtr::_InterlockedExchange( ppvObject, this );
         return S_OK;
      }
      HUnsafePtr::_InterlockedExchange( ppvObject, NULL );
      return E_NOINTERFACE;
   }

// === IPersist methods: ===

   STDMETHODIMP GetClassID(CLSID* pClassID)
   {
      *pClassID = CLSID_NULL; return S_OK;
   }

private:
   $INT _RefCount_;
//--------------------------------------------------------------------------------------------------
}; // HTCOMDummyObject
//==================================================================================================

} // CommonHelpers
