/*
* OBJECT.CPP
*
* Connectable Object implementation that supports the sample
* interface IDuckEvents.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "connect.h"
/*
* CConnObject::CConnObject
* CConnObject::~CConnObject
*
* Constructor Parameters:
* None
*/
CConnObject::CConnObject(void)
{
UINT i;
m_cRef=0;
for (i=0; i < CCONNPOINTS; i++)
m_rgpConnPt[i]=NULL;
return;
}
CConnObject::~CConnObject(void)
{
UINT i;
for (i=0; i < CCONNPOINTS; i++)
{
if (NULL!=m_rgpConnPt[i])
{
if (NULL!=m_rgpConnPt[i])
delete m_rgpConnPt[i];
}
}
return;
}
/*
* CConnObject::Init
*
* Purpose:
* Instantiates the interface implementations for this object.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if initialization succeeds, FALSE otherwise.
*/
BOOL CConnObject::Init(void)
{
UINT i;
//Create our connection points
for (i=0; i < CCONNPOINTS; i++)
{
m_rgpConnPt[i]=new CConnectionPoint(this, IID_IDuckEvents);
if (NULL==m_rgpConnPt[i])
return FALSE;
m_rgpConnPt[i]->AddRef();
}
return TRUE;
}
/*
* CConnObject::QueryInterface
*
* Purpose:
* Manages the interfaces for this object which supports the
* IUnknown, ISampleOne, and ISampleTwo interfaces.
*
* Parameters:
* riid REFIID of the interface to return.
* ppv PPVOID in which to store the pointer.
*
* Return Value:
* HRESULT NOERROR on success, E_NOINTERFACE if the
* interface is not supported.
*/
STDMETHODIMP CConnObject::QueryInterface(REFIID riid, PPVOID ppv)
{
//Always NULL the out-parameters
*ppv=NULL;
if (IID_IUnknown==riid || IID_IConnectionPointContainer==riid)
*ppv=this;
if (NULL==*ppv)
return ResultFromScode(E_NOINTERFACE);
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
/*
* CConnObject::AddRef
* CConnObject::Release
*
* Reference counting members. When Release sees a zero count
* the object destroys itself.
*/
DWORD CConnObject::AddRef(void)
{
return ++m_cRef;
}
DWORD CConnObject::Release(void)
{
if (0!=--m_cRef)
return m_cRef;
delete this;
return 0;
}
/*
* CConnObject::EnumConnectionPoints
*
* Purpose:
* Creates and returns an enumerator object with the
* IEnumConnectionPoints interface that will enumerate the
* individual connection points supported in this object.
*
* Parameters:
* ppEnum LPENUMCONNECTIONPOINTS in which to store the
* IEnumConnectionPoints pointer.
*
* Return Value:
* HRESULT NOERROR on success, E_OUTOFMEMORY on failure or
* other error code.
*/
STDMETHODIMP CConnObject::EnumConnectionPoints
(LPENUMCONNECTIONPOINTS *ppEnum)
{
IConnectionPoint *rgCP[CCONNPOINTS];
UINT i;
PCEnumConnectionPoints pEnum;
*ppEnum=NULL;
for (i=0; i < CCONNPOINTS; i++)
rgCP[i]=(IConnectionPoint *)m_rgpConnPt[i];
//Create the enumerator: we only have one connection point
pEnum=new CEnumConnectionPoints(this, CCONNPOINTS, rgCP);
if (NULL==pEnum)
return ResultFromScode(E_OUTOFMEMORY);
pEnum->AddRef();
*ppEnum=pEnum;
return NOERROR;
}
/*
* CConnObject::FindConnectionPoint
*
* Purpose:
* Returns a pointer to the IConnectionPoint for a given
* outgoing IID.
*
* Parameters:
* riid REFIID of the outgoing interface for which
* a connection point is desired.
* ppCP IConnectionPoint ** in which to return
* the pointer after calling AddRef.
*
* Return Value:
* HRESULT NOERROR if the connection point is found,
* E_NOINTERFACE if it's not supported.
*/
STDMETHODIMP CConnObject::FindConnectionPoint(REFIID riid
, IConnectionPoint **ppCP)
{
*ppCP=NULL;
if (IID_IDuckEvents==riid)
{
return m_rgpConnPt[0]->QueryInterface(IID_IConnectionPoint
, (PPVOID)ppCP);
}
return ResultFromScode(E_NOINTERFACE);
}
/*
* CConnObject::TriggerEvent
*
* Purpose:
* Functions to make each connection point generate calls
* to any connected sinks. Since these functions are specific
* to IDuckEvents, they only deal with the connection point
* for that one interface
*
* Parameters:
* iEvent UINT of the event to trigger, either
* EVENT_QUACK, EVENT_FLAP, or EVENT_PADDLE.
*
* Return Value:
* BOOL TRUE events are triggered, FALSE if there
* are no connected sinks.
*/
BOOL CConnObject::TriggerEvent(UINT iEvent)
{
IEnumConnections *pEnum;
CONNECTDATA cd;
if (FAILED(m_rgpConnPt[0]->EnumConnections(&pEnum)))
return FALSE;
while (NOERROR==pEnum->Next(1, &cd, NULL))
{
IDuckEvents *pDuck;
if (SUCCEEDED(cd.pUnk->QueryInterface(IID_IDuckEvents
, (PPVOID)&pDuck)))
{
switch (iEvent)
{
case EVENT_QUACK:
pDuck->Quack();
break;
case EVENT_FLAP:
pDuck->Flap();
break;
case EVENT_PADDLE:
pDuck->Paddle();
break;
}
pDuck->Release();
}
cd.pUnk->Release();
}
pEnum->Release();
return TRUE;
}
//Connection Point Enumerator follows
/*
* CEnumConnectionPoints::CEnumConnectionPoints
* CEnumConnectionPoints::~CEnumConnectionPoints
*
* Parameters (Constructor):
* pUnkRef LPUNKNOWN to use for reference counting.
* cPoints ULONG number of connection points in prgpCP
* rgpCP IConnectionPoint** to the array to enumerate.
*/
CEnumConnectionPoints::CEnumConnectionPoints(LPUNKNOWN pUnkRef
, ULONG cPoints, IConnectionPoint **rgpCP)
{
UINT i;
m_cRef=0;
m_pUnkRef=pUnkRef;
m_iCur=0;
m_cPoints=cPoints;
m_rgpCP=new IConnectionPoint *[(UINT)cPoints];
if (NULL!=m_rgpCP)
{
for (i=0; i < cPoints; i++)
{
m_rgpCP[i]=rgpCP[i];
m_rgpCP[i]->AddRef();
}
}
return;
}
CEnumConnectionPoints::~CEnumConnectionPoints(void)
{
if (NULL!=m_rgpCP)
{
UINT i;
for (i=0; i < m_cPoints; i++)
m_rgpCP[i]->Release();
delete [] m_rgpCP;
}
return;
}
/*
* CEnumConnectionPoints::QueryInterface
* CEnumConnectionPoints::AddRef
* CEnumConnectionPoints::Release
*
* Purpose:
* IUnknown members for CEnumConnectionPoints object.
*/
STDMETHODIMP CEnumConnectionPoints::QueryInterface(REFIID riid
, LPVOID *ppv)
{
*ppv=NULL;
if (IID_IUnknown==riid || IID_IEnumConnectionPoints==riid)
*ppv=(LPVOID)this;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CEnumConnectionPoints::AddRef(void)
{
++m_cRef;
m_pUnkRef->AddRef();
return m_cRef;
}
STDMETHODIMP_(ULONG) CEnumConnectionPoints::Release(void)
{
m_pUnkRef->Release();
if (0L!=--m_cRef)
return m_cRef;
delete this;
return 0;
}
/*
* CEnumConnectionPoints::Next
*
* Purpose:
* Returns the next element in the enumeration.
*
* Parameters:
* cPoints ULONG number of connection points to return.
* ppCP IConnectionPoint** in which to store the returned
* pointers.
* pulEnum ULONG * in which to return how many we
* enumerated.
*
* Return Value:
* HRESULT NOERROR if successful, S_FALSE otherwise,
*/
STDMETHODIMP CEnumConnectionPoints::Next(ULONG cPoints
, IConnectionPoint **ppCP, ULONG *pulEnum)
{
ULONG cReturn=0L;
if (NULL==m_rgpCP)
return ResultFromScode(S_FALSE);
if (NULL==ppCP)
return ResultFromScode(E_POINTER);
if (NULL==pulEnum)
{
if (1L!=cPoints)
return ResultFromScode(E_POINTER);
}
else
*pulEnum=0L;
if (NULL==*ppCP || m_iCur >= m_cPoints)
return ResultFromScode(S_FALSE);
while (m_iCur < m_cPoints && cPoints > 0)
{
*ppCP=m_rgpCP[m_iCur++];
if (NULL!=*ppCP)
(*ppCP)->AddRef();
ppCP++;
cReturn++;
cPoints--;
}
if (NULL!=pulEnum)
*pulEnum=cReturn;
return NOERROR;
}
STDMETHODIMP CEnumConnectionPoints::Skip(ULONG cSkip)
{
if (((m_iCur+cSkip) >= m_cPoints) || NULL==m_rgpCP)
return ResultFromScode(S_FALSE);
m_iCur+=cSkip;
return NOERROR;
}
STDMETHODIMP CEnumConnectionPoints::Reset(void)
{
m_iCur=0;
return NOERROR;
}
STDMETHODIMP CEnumConnectionPoints::Clone
(LPENUMCONNECTIONPOINTS *ppEnum)
{
PCEnumConnectionPoints pNew;
*ppEnum=NULL;
//Create the clone
pNew=new CEnumConnectionPoints(m_pUnkRef, m_cPoints, m_rgpCP);
if (NULL==pNew)
return ResultFromScode(E_OUTOFMEMORY);
pNew->AddRef();
pNew->m_iCur=m_iCur;
*ppEnum=pNew;
return NOERROR;
}