564 lines
12 KiB
C++
564 lines
12 KiB
C++
// File: connpnts.cpp
|
||
//
|
||
// CConnectionPoint
|
||
// CConnectionPointContainer
|
||
// CEnumConnections
|
||
///////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "precomp.h"
|
||
#include "connpnts.h"
|
||
|
||
#include <olectl.h>
|
||
|
||
|
||
/* C C O N N E C T I O N P O I N T */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: CConnectionPoint
|
||
|
||
-------------------------------------------------------------------------*/
|
||
CConnectionPoint::CConnectionPoint(const IID *pIID, IConnectionPointContainer *pCPCInit) :
|
||
m_riid(*pIID),
|
||
m_pCPC(pCPCInit),
|
||
m_cSinks(0),
|
||
m_cAllocatedSinks(0),
|
||
m_rgSinks(NULL)
|
||
{
|
||
TRACE_OUT(("CConnectionPoint - Constructed(%08X)", this));
|
||
}
|
||
|
||
CConnectionPoint::~CConnectionPoint (void)
|
||
{
|
||
for (ULONG x = 0; x < m_cAllocatedSinks; x += 1)
|
||
{
|
||
if (m_rgSinks[x] != NULL)
|
||
{
|
||
IUnknown *pUnk = (IUnknown *)m_rgSinks[x];
|
||
pUnk->Release();
|
||
}
|
||
}
|
||
|
||
if (m_cAllocatedSinks != 0)
|
||
{
|
||
HeapFree(GetProcessHeap(), 0, m_rgSinks);
|
||
}
|
||
|
||
TRACE_OUT(("CConnectionPoint - Destructed(%p)", this));
|
||
}
|
||
|
||
STDMETHODIMP_(ULONG) CConnectionPoint::AddRef(void)
|
||
{
|
||
return RefCount::AddRef();
|
||
}
|
||
|
||
STDMETHODIMP_(ULONG) CConnectionPoint::Release(void)
|
||
{
|
||
return RefCount::Release();
|
||
}
|
||
|
||
STDMETHODIMP CConnectionPoint::QueryInterface(REFIID riid, void **ppv)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
if ((riid == IID_IUnknown) || (riid == IID_IConnectionPoint))
|
||
{
|
||
*ppv = (IConnectionPoint *)this;
|
||
TRACE_OUT(("CConnectionPoint::QueryInterface(): Returning IConnectionPoint."));
|
||
}
|
||
else
|
||
{
|
||
hr = E_NOINTERFACE;
|
||
*ppv = NULL;
|
||
TRACE_OUT(("CConnectionPoint::QueryInterface(): Called on unknown interface."));
|
||
}
|
||
|
||
if (S_OK == hr)
|
||
{
|
||
AddRef();
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
|
||
/* N O T I F Y */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: Notify
|
||
|
||
-------------------------------------------------------------------------*/
|
||
STDMETHODIMP CConnectionPoint::Notify(void *pv, CONN_NOTIFYPROC pfn)
|
||
{
|
||
//
|
||
// Enumerate each connection
|
||
//
|
||
|
||
AddRef();
|
||
for (ULONG x = 0; x < m_cAllocatedSinks; x += 1)
|
||
{
|
||
if (m_rgSinks[x] != NULL)
|
||
{
|
||
IUnknown *pUnk = (IUnknown *)m_rgSinks[x];
|
||
pUnk->AddRef();
|
||
(*pfn)(pUnk, pv, m_riid);
|
||
pUnk->Release();
|
||
}
|
||
}
|
||
|
||
Release();
|
||
return S_OK;
|
||
}
|
||
|
||
/* G E T C O N N E C T I O N I N T E R F A C E */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: GetConnectionInterface
|
||
|
||
-------------------------------------------------------------------------*/
|
||
STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID)
|
||
{
|
||
// Validate the parameter
|
||
//
|
||
if (pIID == NULL)
|
||
return E_POINTER;
|
||
|
||
// Support only one connection interface
|
||
//
|
||
*pIID = m_riid;
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer **ppCPC)
|
||
{
|
||
// Validate the parameter
|
||
//
|
||
if (ppCPC == NULL)
|
||
return E_POINTER;
|
||
|
||
// Return the container and add its reference count
|
||
//
|
||
*ppCPC = m_pCPC;
|
||
|
||
if (m_pCPC != NULL)
|
||
{
|
||
// The container is still alive
|
||
//
|
||
m_pCPC->AddRef();
|
||
return S_OK;
|
||
}
|
||
else
|
||
{
|
||
// The container no longer exists
|
||
//
|
||
return E_FAIL;
|
||
}
|
||
}
|
||
|
||
/* A D V I S E */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: Advise
|
||
|
||
-------------------------------------------------------------------------*/
|
||
STDMETHODIMP CConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
|
||
{
|
||
IUnknown *pSinkInterface;
|
||
|
||
// Validate the parameter
|
||
//
|
||
if (pdwCookie == NULL)
|
||
return E_POINTER;
|
||
|
||
*pdwCookie = 0;
|
||
if (pUnk == NULL)
|
||
return E_INVALIDARG;
|
||
|
||
HRESULT hr = CONNECT_E_CANNOTCONNECT;
|
||
|
||
//
|
||
// Get the sink interface
|
||
//
|
||
|
||
if (SUCCEEDED(pUnk->QueryInterface(m_riid, (void **)&pSinkInterface)))
|
||
{
|
||
|
||
//
|
||
// If the number of active sinks is less than the number of allocated
|
||
// sinks, then there is a free slot in the sink table. Otherwise, the
|
||
// table must be expanded.
|
||
//
|
||
|
||
ULONG x = m_cAllocatedSinks;
|
||
if (m_cSinks < m_cAllocatedSinks)
|
||
{
|
||
for (x = 0; x < m_cAllocatedSinks; x += 1)
|
||
{
|
||
if (m_rgSinks[x] == NULL)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If a free slot was found in the table, then use the slot. Otherwise,
|
||
// expand the sink table.
|
||
//
|
||
|
||
if (x == m_cAllocatedSinks)
|
||
{
|
||
IUnknown **rgSinks = (IUnknown **)HeapAlloc(GetProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
(m_cAllocatedSinks + 8) * sizeof(IUnknown *));
|
||
|
||
if (rgSinks == NULL)
|
||
{
|
||
pSinkInterface->Release();
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
|
||
for (ULONG z = 0; z < m_cAllocatedSinks; z += 1)
|
||
{
|
||
rgSinks[z] = m_rgSinks[z];
|
||
}
|
||
|
||
m_cAllocatedSinks += 8;
|
||
if (m_rgSinks != NULL) {
|
||
HeapFree(GetProcessHeap(), 0, m_rgSinks);
|
||
}
|
||
|
||
m_rgSinks = rgSinks;
|
||
}
|
||
|
||
//
|
||
// Add new sink to the table.
|
||
//
|
||
|
||
m_rgSinks[x] = pSinkInterface;
|
||
m_cSinks += 1;
|
||
*pdwCookie = x + 1;
|
||
hr = S_OK;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
/* U N A D V I S E */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: Unadvise
|
||
|
||
-------------------------------------------------------------------------*/
|
||
STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie)
|
||
{
|
||
HRESULT hr = CONNECT_E_NOCONNECTION;
|
||
|
||
//
|
||
// Traverse the sink list to find the specified sink object
|
||
//
|
||
|
||
if ((dwCookie != 0) &&
|
||
(dwCookie <= m_cAllocatedSinks) &&
|
||
(m_rgSinks[dwCookie - 1] != NULL))
|
||
{
|
||
IUnknown *pUnk = (IUnknown *) m_rgSinks[dwCookie - 1];
|
||
pUnk->Release();
|
||
m_rgSinks[dwCookie - 1] = NULL;
|
||
m_cSinks -= 1;
|
||
hr = S_OK;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
STDMETHODIMP CConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
|
||
{
|
||
HRESULT hr = E_POINTER;
|
||
|
||
// Validate parameters
|
||
//
|
||
if (ppEnum == NULL)
|
||
{
|
||
// Create an enumerator
|
||
//
|
||
*ppEnum = new CEnumConnections(m_rgSinks, m_cSinks, m_cAllocatedSinks);
|
||
hr = (NULL != *ppEnum) ? S_OK : E_OUTOFMEMORY;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////
|
||
|
||
/* C E N U M C O N N E C T I O N S */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: CEnumConnections
|
||
|
||
-------------------------------------------------------------------------*/
|
||
CEnumConnections::CEnumConnections(IUnknown **pSinks, ULONG cSinks, ULONG cAllocatedSinks) :
|
||
m_iIndex(0),
|
||
m_cConnections(0),
|
||
m_pCD(NULL)
|
||
{
|
||
// Snapshot the connection list
|
||
//
|
||
if (cSinks > 0)
|
||
{
|
||
m_pCD = new CONNECTDATA[cSinks];
|
||
if (NULL != m_pCD)
|
||
{
|
||
for (ULONG x = 0; x < cAllocatedSinks; x += 1)
|
||
{
|
||
if (pSinks[x] != NULL) {
|
||
IUnknown *pUnk = (IUnknown *) pSinks[x];
|
||
pUnk->AddRef();
|
||
m_pCD[m_cConnections++].pUnk = pUnk;
|
||
m_pCD[m_cConnections++].dwCookie = x + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
TRACE_OUT(("CEnumConnections - Constructed(%p)", this));
|
||
}
|
||
|
||
CEnumConnections::~CEnumConnections(void)
|
||
{
|
||
if (m_pCD != NULL)
|
||
{
|
||
for (int i = 0; i < m_cConnections; i++)
|
||
{
|
||
m_pCD[i].pUnk->Release();
|
||
};
|
||
delete [] m_pCD;
|
||
};
|
||
|
||
TRACE_OUT(("CEnumConnections - Destructed(%08X)", this));
|
||
}
|
||
|
||
STDMETHODIMP_(ULONG) CEnumConnections::AddRef(void)
|
||
{
|
||
return RefCount::AddRef();
|
||
}
|
||
|
||
STDMETHODIMP_(ULONG) CEnumConnections::Release(void)
|
||
{
|
||
return RefCount::Release();
|
||
}
|
||
|
||
STDMETHODIMP CEnumConnections::QueryInterface(REFIID riid, void **ppv)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
if ((riid == IID_IEnumConnections) || (riid == IID_IUnknown))
|
||
{
|
||
*ppv = (IEnumConnections *)this;
|
||
TRACE_OUT(("CEnumConnections::QueryInterface(): Returning IEnumConnections."));
|
||
}
|
||
else
|
||
{
|
||
hr = E_NOINTERFACE;
|
||
*ppv = NULL;
|
||
TRACE_OUT(("CEnumConnections::QueryInterface(): Called on unknown interface."));
|
||
}
|
||
|
||
if (S_OK == hr)
|
||
{
|
||
AddRef();
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
STDMETHODIMP CEnumConnections::Next(ULONG cConnections, CONNECTDATA *rgpcd, ULONG *pcFetched)
|
||
{
|
||
ULONG cCopied = 0;
|
||
|
||
if ((0 == cConnections) && (NULL == rgpcd) && (NULL != pcFetched))
|
||
{
|
||
// Return the number of remaining elements
|
||
*pcFetched = m_cConnections - m_iIndex;
|
||
return S_OK;
|
||
}
|
||
|
||
if ((NULL == rgpcd) || ((NULL == pcFetched) && (cConnections != 1)))
|
||
return E_POINTER;
|
||
|
||
if (NULL != m_pCD)
|
||
{
|
||
while ((cCopied < cConnections) && (m_iIndex < m_cConnections))
|
||
{
|
||
*rgpcd = m_pCD[m_iIndex];
|
||
(*rgpcd).pUnk->AddRef();
|
||
rgpcd++;
|
||
cCopied++;
|
||
m_iIndex++;
|
||
}
|
||
}
|
||
|
||
if (pcFetched != NULL)
|
||
*pcFetched = cCopied;
|
||
|
||
return (cConnections == cCopied) ? S_OK : S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP CEnumConnections::Skip(ULONG cConnections)
|
||
{
|
||
m_iIndex += cConnections;
|
||
if (m_iIndex >= m_cConnections)
|
||
{
|
||
// Past the end of the list
|
||
m_iIndex = m_cConnections;
|
||
return S_FALSE;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
STDMETHODIMP CEnumConnections::Reset(void)
|
||
{
|
||
m_iIndex = 0;
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CEnumConnections::Clone(IEnumConnections **ppEnum)
|
||
{
|
||
// Validate parameters
|
||
//
|
||
if (ppEnum != NULL)
|
||
return E_POINTER;
|
||
|
||
HRESULT hr = S_OK;
|
||
CEnumConnections * pEnum = new CEnumConnections(NULL, 0, 0);
|
||
if (NULL == pEnum)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else if (NULL != m_pCD)
|
||
{
|
||
pEnum->m_pCD = new CONNECTDATA[m_cConnections];
|
||
if (NULL == pEnum->m_pCD)
|
||
{
|
||
delete pEnum;
|
||
pEnum = NULL;
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else
|
||
{
|
||
pEnum->m_iIndex = m_iIndex;
|
||
pEnum->m_cConnections = m_cConnections;
|
||
|
||
for (int i = 0; i < m_cConnections; ++i)
|
||
{
|
||
m_pCD[i].pUnk->AddRef();
|
||
pEnum->m_pCD[i] = m_pCD[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
*ppEnum = pEnum;
|
||
return hr;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////
|
||
|
||
/* C C O N N E C T I O N P O I N T C O N T A I N E R */
|
||
/*-------------------------------------------------------------------------
|
||
%%Function: CConnectionPointContainer
|
||
|
||
-------------------------------------------------------------------------*/
|
||
CConnectionPointContainer::CConnectionPointContainer(const IID **ppiid, int cCp) :
|
||
m_ppCp(NULL),
|
||
m_cCp(0)
|
||
{
|
||
m_ppCp = new CConnectionPoint* [cCp];
|
||
if (NULL != m_ppCp)
|
||
{
|
||
for (int i = 0; i < cCp; ++i)
|
||
{
|
||
CConnectionPoint *pCp = new CConnectionPoint(ppiid[i], this);
|
||
if (NULL != pCp)
|
||
{
|
||
m_ppCp[m_cCp++] = pCp;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
CConnectionPointContainer::~CConnectionPointContainer()
|
||
{
|
||
if (NULL != m_ppCp)
|
||
{
|
||
for (int i = 0; i < m_cCp; ++i)
|
||
{
|
||
CConnectionPoint *pCp = m_ppCp[i];
|
||
if (NULL != pCp)
|
||
{
|
||
pCp->ContainerReleased();
|
||
pCp->Release();
|
||
}
|
||
}
|
||
delete[] m_ppCp;
|
||
}
|
||
}
|
||
|
||
|
||
HRESULT STDMETHODCALLTYPE
|
||
CConnectionPointContainer::NotifySink(void *pv, CONN_NOTIFYPROC pfn)
|
||
{
|
||
if (NULL != m_ppCp)
|
||
{
|
||
for (int i = 0; i < m_cCp; ++i)
|
||
{
|
||
m_ppCp[i]->Notify(pv, pfn);
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP
|
||
CConnectionPointContainer::EnumConnectionPoints(IEnumConnectionPoints **ppEnum)
|
||
{
|
||
if (ppEnum == NULL)
|
||
return E_POINTER;
|
||
|
||
// Create an enumerator
|
||
*ppEnum = new CEnumConnectionPoints(m_ppCp, m_cCp);
|
||
|
||
return (NULL != *ppEnum) ? S_OK : E_OUTOFMEMORY;
|
||
}
|
||
|
||
STDMETHODIMP
|
||
CConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCp)
|
||
{
|
||
HRESULT hr = E_POINTER;
|
||
if (NULL != ppCp)
|
||
{
|
||
hr = CONNECT_E_NOCONNECTION;
|
||
*ppCp = NULL;
|
||
|
||
if (NULL != m_ppCp)
|
||
{
|
||
for (int i = 0; i < m_cCp; ++i)
|
||
{
|
||
IID iid;
|
||
IConnectionPoint *pCp = m_ppCp[i];
|
||
if (S_OK == pCp->GetConnectionInterface(&iid))
|
||
{
|
||
if (riid == iid)
|
||
{
|
||
pCp->AddRef();
|
||
*ppCp = pCp;
|
||
hr = S_OK;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
|
||
|