windows-nt/Source/XPSP1/NT/net/tapi/skywalker/confmsp/confpart.cpp

1342 lines
28 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
confpart.cpp
Abstract:
This module contains implementation of the participant classes.
Author:
Mu Han (muhan) 15-September-1999
--*/
#include "stdafx.h"
#include "common.h"
#include "confpart.h"
#ifdef DEBUG_REFCOUNT
ULONG CParticipant::InternalAddRef()
{
ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalAddRef();
LOG((MSP_TRACE, "%p, %s Addref, ref = %d",
this, (m_InfoItems[0]) ? m_InfoItems[0] : "new participant", lRef));
return lRef;
}
ULONG CParticipant::InternalRelease()
{
ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalRelease();
LOG((MSP_TRACE, "%p, %s Release, ref = %d",
this, (m_InfoItems[0]) ? m_InfoItems[0] : "new participant", lRef));
return lRef;
}
#endif
CParticipant::CParticipant()
: m_pFTM(NULL),
m_dwSendingMediaTypes(0),
m_dwReceivingMediaTypes(0)
{
// initialize the info item array.
ZeroMemory(m_InfoItems, sizeof(char *) * (RTCP_SDES_LAST - 1));
}
// methods called by the call object.
HRESULT CParticipant::Init(
IN char * szCName,
IN ITStream * pITStream,
IN DWORD dwSSRC,
IN DWORD dwSendRecv,
IN DWORD dwMediaType
)
/*++
Routine Description:
Initialize the participant object.
Arguments:
szCName - the canonical name of the participant.
pITStream - the stream that has the participant.
dwSSRC - the SSRC of the participant in that stream.
dwSendRecv - a sender or a receiver.
dwMediaType - the media type of the participant.
Return Value:
S_OK,
E_OUTOFMEMORY.
--*/
{
LOG((MSP_TRACE, "CParticipant::Init, name:%s", szCName));
// create the marshaler.
HRESULT hr;
hr = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pFTM);
if (FAILED(hr))
{
LOG((MSP_ERROR, "create marshaler failed, %x", hr));
return hr;
}
m_InfoItems[0] = (char *)malloc(lstrlenA(szCName) + 1);
if (m_InfoItems[0] == NULL)
{
LOG((MSP_ERROR, "out of mem for CName"));
return E_OUTOFMEMORY;
}
lstrcpyA(m_InfoItems[0], szCName);
// add the stream into out list.
hr = AddStream(pITStream, dwSSRC, dwSendRecv, dwMediaType);
if (FAILED(hr))
{
LOG((MSP_ERROR, "failed to add stream %x", hr));
return hr;
}
LOG((MSP_TRACE, "CParticipant: %s, Init returns S_OK", szCName));
return S_OK;
}
BOOL CParticipant::UpdateInfo(
IN int Type,
IN DWORD dwLen,
IN char * szInfo
)
/*++
Routine Description:
Update one item of the participant info.
Arguments:
Type - the type of the INFO,
dwLen - the length of the information.
szInfo - the information.
Return Value:
TRUE - information changed.
FALSE - the information is the same, no change was made.
--*/
{
int index = Type - 1;
// if we have an item already, find out if it is the same.
if (m_InfoItems[index] != NULL)
{
if (lstrcmpA(m_InfoItems[index], szInfo) == 0)
{
return FALSE;
}
// if the item is new, free the old one
free(m_InfoItems[index]);
}
// allocate memory and store it.
m_InfoItems[index] = (char *)malloc(dwLen + 1);
if (m_InfoItems[index] == NULL)
{
return FALSE;
}
lstrcpynA(m_InfoItems[index], szInfo, dwLen);
return TRUE;
}
BOOL CParticipant::UpdateSSRC(
IN ITStream * pITStream,
IN DWORD dwSSRC,
IN DWORD dwSendRecv
)
/*++
Routine Description:
Update the SSRC for a stream.
Arguments:
pITStream - the stream that the participant is on.
dwSSRC - the SSRC of the participant.
dwSendRecv - the participant is a sender or a receiver.
Return Value:
TRUE - information changed.
FALSE - the stream is not found.
--*/
{
CLock lock(m_lock);
// if the stream is already there, update the SSRC and return.
int index = m_Streams.Find(pITStream);
if ( index >= 0)
{
m_StreamInfo[index].dwSSRC = dwSSRC;
m_StreamInfo[index].dwSendRecv |= dwSendRecv;
return TRUE;
}
return FALSE;
}
BOOL CParticipant::HasSSRC(
IN ITStream * pITStream,
IN DWORD dwSSRC
)
/*++
Routine Description:
find out if the participant has the SSRC for a stream.
Arguments:
pITStream - the stream that the participant is on.
dwSSRC - the SSRC of the participant.
Return Value:
TRUE - the SSRC exists.
FALSE - the SSRC does not exist.
--*/
{
CLock lock(m_lock);
int index = m_Streams.Find(pITStream);
if (index >= 0)
{
return (m_StreamInfo[index].dwSSRC == dwSSRC);
}
return FALSE;
}
BOOL CParticipant::GetSSRC(
IN ITStream * pITStream,
OUT DWORD * pdwSSRC
)
/*++
Routine Description:
Update the SSRC for a stream.
Arguments:
pITStream - the stream that the participant is on.
pdwSSRC - the address to store the SSRC of the participant.
Return Value:
TRUE - the SSRC is found.
FALSE - the SSRC is not found.
--*/
{
CLock lock(m_lock);
// if the stream is already there, update the SSRC and return.
int index = m_Streams.Find(pITStream);
if ( index >= 0)
{
*pdwSSRC = m_StreamInfo[index].dwSSRC;
return TRUE;
}
return FALSE;
}
DWORD CParticipant::GetSendRecvStatus(
IN ITStream * pITStream
)
/*++
Routine Description:
find out the current send and recv status on a given stream.
Arguments:
pITStream - the stream that the participant is on.
Return Value:
A bit mask of send and receive status
--*/
{
CLock lock(m_lock);
int index = m_Streams.Find(pITStream);
if (index >= 0)
{
return m_StreamInfo[index].dwSendRecv;
}
return 0;
}
void CParticipant::FinalRelease()
/*++
Routine Description:
release everything before being deleted.
Arguments:
Return Value:
--*/
{
LOG((MSP_TRACE, "CParticipant::FinalRelease, name %s", m_InfoItems[0]));
if (m_pFTM)
{
m_pFTM->Release();
}
for (int i = 0; i < RTCP_SDES_LAST - 1; i ++)
{
if (m_InfoItems[i])
{
free(m_InfoItems[i]);
}
}
for (i = 0; i < m_Streams.GetSize(); i ++)
{
m_Streams[i]->Release();
}
m_Streams.RemoveAll();
LOG((MSP_TRACE, "CParticipant::FinalRelease - exit"));
}
// ITParticipant methods, called by the app.
STDMETHODIMP CParticipant::get_ParticipantTypedInfo(
IN PARTICIPANT_TYPED_INFO InfoType,
OUT BSTR * ppInfo
)
/*++
Routine Description:
Get a information item for this participant.
Arguments:
InfoType - The type of the information asked.
ppInfo - the mem address to store a BSTR.
Return Value:
S_OK,
E_INVALIDARG,
E_POINTER,
E_OUTOFMEMORY,
TAPI_E_NOITEMS
*/
{
LOG((MSP_TRACE, "CParticipant get info, type:%d", InfoType));
if (InfoType > PTI_PRIVATE || InfoType < 0)
{
LOG((MSP_ERROR, "CParticipant get info - exit invalid arg"));
return E_INVALIDARG;
}
if (IsBadWritePtr(ppInfo, sizeof(BSTR)))
{
LOG((MSP_ERROR, "CParticipant get info - exit E_POINTER"));
return E_POINTER;
}
// check if we have that info.
CLock lock(m_lock);
int index = (int)InfoType;
if (m_InfoItems[index] == NULL)
{
LOG((MSP_INFO, "CParticipant get info - no item for %d", InfoType));
return TAPI_E_NOITEMS;
}
// conver the char string to WCHAR string.
WCHAR Buffer[RTP_MAX_SDES + 1];
if (!MultiByteToWideChar(
GetACP(),
0,
m_InfoItems[index],
-1,
Buffer,
RTP_MAX_SDES
))
{
LOG((MSP_ERROR, "coverting failed, error:%x", GetLastError()));
return E_FAIL;
}
// make a BSTR out of it.
BSTR pName = SysAllocString(Buffer);
if (pName == NULL)
{
LOG((MSP_ERROR, "CParticipant get info - exit out of mem"));
return E_OUTOFMEMORY;
}
// return the BSTR.
*ppInfo = pName;
return S_OK;
}
STDMETHODIMP CParticipant::get_MediaTypes(
// IN TERMINAL_DIRECTION Direction,
OUT long * plMediaTypes
)
/*++
Routine Description:
Get the media type of the participant
Arguments:
plMediaType - the mem address to store a long.
Return Value:
S_OK,
E_POINTER,
*/
{
LOG((MSP_TRACE, "CParticipant::get_MediaTypes - enter"));
if (IsBadWritePtr(plMediaTypes, sizeof (long)))
{
LOG((MSP_ERROR, "CParticipant::get_MediaType - exit E_POINTER"));
return E_POINTER;
}
CLock lock(m_lock);
#if 0
if (Direction == TD_RENDER)
{
*plMediaTypes = (long)m_dwReceivingMediaTypes;
}
else
{
*plMediaTypes = (long)m_dwSendingMediaTypes;
}
#endif
*plMediaTypes = (long)(m_dwSendingMediaTypes | m_dwReceivingMediaTypes);
LOG((MSP_TRACE, "CParticipant::get_MediaType:%x - exit S_OK", *plMediaTypes));
return S_OK;
}
STDMETHODIMP CParticipant::put_Status(
IN ITStream * pITStream,
IN VARIANT_BOOL fEnable
)
{
/* this is a new feature, we still can not really control the participant.
LOG((MSP_TRACE, "CParticipant::put_Status, pITStream %p, status %hs",
pITStream, fEnable ? "Enable" : "Disable"
));
HRESULT hr;
// if the caller specified a stream, find the stream and use it.
if (pITStream != NULL)
{
m_lock.Lock();
int index;
if ((index = m_Streams.Find(pITStream)) < 0)
{
m_lock.Unlock();
LOG((MSP_ERROR, "CParticipant::put_Status, stream %p not found",
pITStream,));
return E_INVALIDARG;
}
// add ref so that it won't go away.
pITStream->AddRef();
m_lock.Unlock;
hr = ((CIPConfMSPStream *)pITStream)->EnableParticipant(
fEnable
);
pITStream->Release();
return hr;
}
// if the caller didn't specify a stream, set the status on all streams.
m_lock.Lock();
int nSize = m_Streams.GetSize();
ITStream ** Streams = (ITSTream **)malloc(sizeof(ITStream*) * nSize);
if (Streams == NULL)
{
m_lock.Unlock();
LOG((MSP_ERROR, "CParticipant::put_Status out of memory"));
return E_OUTOFMEMORY;
}
for (int i = 0; i < nSize; i ++)
{
Streams[i] = m_Streams[i];
Streams[i]->AddRef();
}
m_lock.Unlock();
for (i = 0; i < nSize; i ++)
{
hr = Streams[i]->EnableParticipant(fEnable);
if (FAILED(hr))
{
break;
}
}
for (i = 0; i < nSize; i ++)
{
Streams[i]->Release();
}
free(Streams);
return hr;
*/
return E_NOTIMPL;
}
STDMETHODIMP CParticipant::get_Status(
IN ITStream * pITStream,
OUT VARIANT_BOOL * pStatus
)
{
return E_NOTIMPL;
}
STDMETHODIMP CParticipant::EnumerateStreams(
OUT IEnumStream ** ppEnumStream
)
{
LOG((MSP_TRACE,
"EnumerateStreams entered. ppEnumStream:%x", ppEnumStream));
//
// Check parameters.
//
if (IsBadWritePtr(ppEnumStream, sizeof(VOID *)))
{
LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
"bad pointer argument - exit E_POINTER"));
return E_POINTER;
}
//
// First see if this call has been shut down.
// acquire the lock before accessing the stream object list.
//
CLock lock(m_lock);
if (m_Streams.GetData() == NULL)
{
LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
"call appears to have been shut down - exit E_UNEXPECTED"));
// This call has been shut down.
return E_UNEXPECTED;
}
//
// Create an enumerator object.
//
typedef _CopyInterface<ITStream> CCopy;
typedef CSafeComEnum<IEnumStream, &IID_IEnumStream,
ITStream *, CCopy> CEnumerator;
HRESULT hr;
CComObject<CEnumerator> *pEnum = NULL;
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
if (pEnum == NULL)
{
LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
"Could not create enumerator object, %x", hr));
return hr;
}
//
// query for the IID_IEnumStream i/f
//
hr = pEnum->_InternalQueryInterface(IID_IEnumStream, (void**)ppEnumStream);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
"query enum interface failed, %x", hr));
delete pEnum;
return hr;
}
//
// Init the enumerator object. The CSafeComEnum can handle zero-sized array.
//
hr = pEnum->Init(
m_Streams.GetData(), // the begin itor
m_Streams.GetData() + m_Streams.GetSize(), // the end itor,
NULL, // IUnknown
AtlFlagCopy // copy the data.
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
"init enumerator object failed, %x", hr));
(*ppEnumStream)->Release();
return hr;
}
LOG((MSP_TRACE, "CMSPCallBase::EnumerateStreams - exit S_OK"));
return hr;
}
STDMETHODIMP CParticipant::get_Streams(
OUT VARIANT * pVariant
)
{
LOG((MSP_TRACE, "CParticipant::get_Streams - enter"));
//
// Check parameters.
//
if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
{
LOG((MSP_ERROR, "CParticipant::get_Streams - "
"bad pointer argument - exit E_POINTER"));
return E_POINTER;
}
//
// See if this call has been shut down. Acquire the lock before accessing
// the stream object list.
//
CLock lock(m_lock);
if (m_Streams.GetData() == NULL)
{
LOG((MSP_ERROR, "CParticipant::get_Streams - "
"call appears to have been shut down - exit E_UNEXPECTED"));
// This call has been shut down.
return E_UNEXPECTED;
}
//
// create the collection object - see mspcoll.h
//
typedef CTapiIfCollection< ITStream * > StreamCollection;
CComObject<StreamCollection> * pCollection;
HRESULT hr = CComObject<StreamCollection>::CreateInstance( &pCollection );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CParticipant::get_Streams - "
"can't create collection - exit 0x%08x", hr));
return hr;
}
//
// get the Collection's IDispatch interface
//
IDispatch * pDispatch;
hr = pCollection->_InternalQueryInterface(IID_IDispatch,
(void **) &pDispatch );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CParticipant::get_Streams - "
"QI for IDispatch on collection failed - exit 0x%08x", hr));
delete pCollection;
return hr;
}
//
// Init the collection using an iterator -- pointers to the beginning and
// the ending element plus one.
//
hr = pCollection->Initialize( m_Streams.GetSize(),
m_Streams.GetData(),
m_Streams.GetData() + m_Streams.GetSize() );
if (FAILED(hr))
{
LOG((MSP_ERROR, "CParticipant::get_Streams - "
"Initialize on collection failed - exit 0x%08x", hr));
pDispatch->Release();
return hr;
}
//
// put the IDispatch interface pointer into the variant
//
LOG((MSP_INFO, "CParticipant::get_Streams - "
"placing IDispatch value %08x in variant", pDispatch));
VariantInit(pVariant);
pVariant->vt = VT_DISPATCH;
pVariant->pdispVal = pDispatch;
LOG((MSP_TRACE, "CParticipant::get_Streams - exit S_OK"));
return S_OK;
}
HRESULT CParticipant::AddStream(
IN ITStream * pITStream,
IN DWORD dwSSRC,
IN DWORD dwSendRecv,
IN DWORD dwMediaType
)
/*++
Routine Description:
A participant might appear on more than one streams. This function adds
a new stream and the SSRC into the participant's list.
Arguments:
pITStream - the stream that has the participant.
dwSSRC - the SSRC of the participant in that stream.
dwSendRecv - the participant is a sender or receiver in the stream.
dwMediaType - the media type of the stream.
Return Value:
S_OK,
E_OUTOFMEMORY,
*/
{
CLock lock(m_lock);
// if the stream is already there, update the SSRC and return.
int index = m_Streams.Find(pITStream);
if ( index >= 0)
{
m_StreamInfo[index].dwSSRC = dwSSRC;
m_StreamInfo[index].dwSendRecv |= dwSendRecv;
return S_OK;
}
// add the stream.
if (!m_Streams.Add(pITStream))
{
return E_OUTOFMEMORY;
}
// add the SSRC and sender flag.
STREAM_INFO Info;
Info.dwSSRC = dwSSRC;
Info.dwSendRecv = dwSendRecv;
if (!m_StreamInfo.Add(Info))
{
m_Streams.Remove(pITStream);
return E_OUTOFMEMORY;
}
pITStream->AddRef();
// update the mediatype.
if (dwSendRecv & PART_SEND)
{
m_dwSendingMediaTypes |= dwMediaType;
}
if (dwSendRecv & PART_RECV)
{
m_dwReceivingMediaTypes |= dwMediaType;
}
return S_OK;
}
HRESULT CParticipant::RemoveStream(
IN ITStream * pITStream,
IN DWORD dwSSRC,
OUT BOOL * pbLast
)
/*++
Routine Description:
A participant might appear on more than one streams. This function remove
a stream from the participant's list.
Arguments:
pITStream - the stream that has the participant.
dwSSRC - the SSRC of the participant in that stream.
pbLast - the memory space to store a boolean value, specifying if the
stream removed was the last one in the list.
Return Value:
S_OK,
E_POINTER,
*/
{
CLock lock(m_lock);
// first find the stream.
int index = m_Streams.Find(pITStream);
if (index < 0)
{
return E_FAIL;
}
if (m_Streams.GetSize() != m_StreamInfo.GetSize())
{
return E_UNEXPECTED;
}
// then check the SSRC.
if (m_StreamInfo[index].dwSSRC != dwSSRC)
{
// this is not the participant being looking for.
return E_FAIL;
}
// SSRC match, we found the participant. remove the stream and info.
m_Streams.RemoveAt(index);
m_StreamInfo.RemoveAt(index);
// release the refcount we had in the list.
pITStream->Release();
// recalculate the media types.
m_dwSendingMediaTypes = 0;
m_dwReceivingMediaTypes = 0;
for (int i = 0; i < m_Streams.GetSize(); i ++)
{
if (m_StreamInfo[i].dwSendRecv & PART_SEND)
{
m_dwSendingMediaTypes |= ((CIPConfMSPStream *)m_Streams[i])->MediaType();
}
if (m_StreamInfo[i].dwSendRecv & PART_RECV)
{
m_dwReceivingMediaTypes |= ((CIPConfMSPStream *)m_Streams[i])->MediaType();
}
}
*pbLast = (m_Streams.GetSize() == 0);
return S_OK;
}
BOOL CParticipantList::FindByCName(char *szCName, int *pIndex) const
/*++
Routine Description:
Find a participant by its canonical name. If the function returns true,
*pIndex contains the index of the participant. If the function returns
false, *pIndex contains the index where the new participant should be
inserted.
Arguments:
szCName - the canonical name of the participant.
pIndex - the memory address to store an integer.
Return Value:
TRUE - the participant is found.
FALSE - the participant is not in the list.
*/
{
for(int i = 0; i < m_nSize; i++)
{
// This list is an ordered list based on dictionary order. We are using
// a linear search here, it could be changed to a binary search.
// CompareCName will return 0 if the name is the same, <0 if the szCName
// is bigger, >0 if the szCName is smaller.
int res = ((CParticipant *)m_aT[i])->CompareCName(szCName);
if(res >= 0)
{
*pIndex = i;
return (res == 0);
}
}
*pIndex = m_nSize;
return FALSE; // not found
}
BOOL CParticipantList::InsertAt(int nIndex, ITParticipant *pITParticipant)
/*++
Routine Description:
Insert a participant into the list at a given index.
Arguments:
nIndex - the location where the new object is inserted.
pITParticipant - the object to be inserted.
Return Value:
TRUE - the participant is inserted.
FALSE - out of memory.
*/
{
_ASSERTE(nIndex >= 0 && nIndex <= m_nSize);
if(m_nSize == m_nAllocSize)
{
if (!Grow()) return FALSE;
}
memmove((void*)&m_aT[nIndex+1], (void*)&m_aT[nIndex],
(m_nSize - nIndex) * sizeof(ITParticipant *));
m_nSize++;
SetAtIndex(nIndex, pITParticipant);
return TRUE;
}
CParticipantEvent::CParticipantEvent()
: m_pFTM(NULL),
m_pITParticipant(NULL),
m_pITSubStream(NULL),
m_Event(PE_NEW_PARTICIPANT)
{}
// methods called by the call object.
HRESULT CParticipantEvent::Init(
IN PARTICIPANT_EVENT Event,
IN ITParticipant * pITParticipant,
IN ITSubStream * pITSubStream
)
/*++
Routine Description:
Initialize the ParticipantEvent object.
Arguments:
Event - the event.
pITParticipant - the participant.
pITSubStream - the substream, can be NULL.
Return Value:
S_OK,
--*/
{
LOG((MSP_TRACE, "CParticipantEvent::Init"));
// create the marshaler.
HRESULT hr;
hr = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pFTM);
if (FAILED(hr))
{
LOG((MSP_ERROR, "create marshaler failed, %x", hr));
return hr;
}
m_Event = Event;
m_pITParticipant = pITParticipant;
if (m_pITParticipant) m_pITParticipant->AddRef();
m_pITSubStream = pITSubStream;
if (m_pITSubStream) m_pITSubStream->AddRef();
LOG((MSP_TRACE, "CParticipantEvent Init returns S_OK"));
return S_OK;
}
void CParticipantEvent::FinalRelease()
/*++
Routine Description:
release everything before being deleted.
Arguments:
Return Value:
--*/
{
LOG((MSP_TRACE, "CParticipantEvent::FinalRelease - enter"));
if (m_pFTM)
{
m_pFTM->Release();
}
if (m_pITParticipant) m_pITParticipant->Release();
if (m_pITSubStream) m_pITSubStream->Release();
LOG((MSP_TRACE, "CParticipantEvent::FinalRelease - exit"));
}
STDMETHODIMP CParticipantEvent::get_Event(
OUT PARTICIPANT_EVENT * pParticipantEvent
)
{
if (IsBadWritePtr(pParticipantEvent, sizeof (PARTICIPANT_EVENT)))
{
LOG((MSP_ERROR, "CParticipantEvent::get_Event - exit E_POINTER"));
return E_POINTER;
}
*pParticipantEvent = m_Event;
return S_OK;
}
STDMETHODIMP CParticipantEvent::get_Participant(
OUT ITParticipant ** ppITParticipant
)
{
if (IsBadWritePtr(ppITParticipant, sizeof (void *)))
{
LOG((MSP_ERROR, "CParticipantEvent::get_participant - exit E_POINTER"));
return E_POINTER;
}
if (!m_pITParticipant)
{
LOG((MSP_ERROR, "CParticipantevnt::get_Participant - exit no item"));
return TAPI_E_NOITEMS;
}
m_pITParticipant->AddRef();
*ppITParticipant = m_pITParticipant;
return S_OK;
}
STDMETHODIMP CParticipantEvent::get_SubStream(
OUT ITSubStream** ppSubStream
)
{
if (IsBadWritePtr(ppSubStream, sizeof (void *)))
{
LOG((MSP_ERROR, "CParticipantEvent::get_SubStream - exit E_POINTER"));
return E_POINTER;
}
if (!m_pITSubStream)
{
LOG((MSP_WARN, "CParticipantevnt::get_SubStream - exit no item"));
return TAPI_E_NOITEMS;
}
m_pITSubStream->AddRef();
*ppSubStream = m_pITSubStream;
return S_OK;
}
HRESULT CreateParticipantEvent(
IN PARTICIPANT_EVENT Event,
IN ITParticipant * pITParticipant,
IN ITSubStream * pITSubStream,
OUT IDispatch ** ppIDispatch
)
{
// create the object.
CComObject<CParticipantEvent> * pCOMParticipantEvent;
HRESULT hr = CComObject<CParticipantEvent>
::CreateInstance(&pCOMParticipantEvent);
if (NULL == pCOMParticipantEvent)
{
LOG((MSP_ERROR, "could not create participant event:%x", hr));
return hr;
}
IDispatch * pIDispatch;
// get the interface pointer.
hr = pCOMParticipantEvent->_InternalQueryInterface(
IID_IDispatch,
(void **)&pIDispatch
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "Create ParticipantEvent QueryInterface failed: %x", hr));
delete pCOMParticipantEvent;
return hr;
}
// Initialize the object.
hr = pCOMParticipantEvent->Init(
Event,
pITParticipant,
pITSubStream
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CreateMSPParticipantEvent:call init failed: %x", hr));
pIDispatch->Release();
return hr;
}
*ppIDispatch = pIDispatch;
return S_OK;
}
HRESULT CreateParticipantEnumerator(
IN ITParticipant ** begin,
IN ITParticipant ** end,
OUT IEnumParticipant ** ppEnumParticipant
)
{
//
// Create an enumerator object.
//
typedef _CopyInterface<ITParticipant> CCopy;
typedef CSafeComEnum<IEnumParticipant, &IID_IEnumParticipant,
ITParticipant *, CCopy> CEnumerator;
HRESULT hr;
CComObject<CEnumerator> *pEnum = NULL;
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
if (pEnum == NULL)
{
LOG((MSP_ERROR, "CreateParticipantEnumerator - "
"Could not create enumerator object, %x", hr));
return hr;
}
//
// query for the IID_IEnumParticipant i/f
//
hr = pEnum->_InternalQueryInterface(
IID_IEnumParticipant,
(void**)ppEnumParticipant
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CreateParticipantEnumerator - "
"query enum interface failed, %x", hr));
delete pEnum;
return hr;
}
//
// Init the enumerator object. The CSafeComEnum can handle zero-sized array.
//
hr = pEnum->Init(
begin, // the begin itor
end, // the end itor,
NULL, // IUnknown
AtlFlagCopy // copy the data.
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CreateParticipantEnumerator - "
"init enumerator object failed, %x", hr));
(*ppEnumParticipant)->Release();
return hr;
}
LOG((MSP_TRACE, "CreateParticipantEnumerator - exit S_OK"));
return hr;
}
HRESULT CreateParticipantCollection(
IN ITParticipant ** begin,
IN ITParticipant ** end,
IN int nSize,
OUT VARIANT * pVariant
)
{
//
// create the collection object - see mspcoll.h
//
typedef CTapiIfCollection< ITParticipant * > ParticipantCollection;
CComObject<ParticipantCollection> * pCollection;
HRESULT hr = CComObject<ParticipantCollection>::CreateInstance( &pCollection );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateParticipantCollection - "
"can't create collection - exit 0x%08x", hr));
return hr;
}
//
// get the Collection's IDispatch interface
//
IDispatch * pDispatch;
hr = pCollection->_InternalQueryInterface(IID_IDispatch,
(void **) &pDispatch );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateParticipantCollection - "
"QI for IDispatch on collection failed - exit 0x%08x", hr));
delete pCollection;
return hr;
}
//
// Init the collection using an iterator -- pointers to the beginning and
// the ending element plus one.
//
hr = pCollection->Initialize(nSize, begin, end);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CreateParticipantCollection- "
"Initialize on collection failed - exit 0x%08x", hr));
pDispatch->Release();
return hr;
}
//
// put the IDispatch interface pointer into the variant
//
VariantInit(pVariant);
pVariant->vt = VT_DISPATCH;
pVariant->pdispVal = pDispatch;
LOG((MSP_TRACE, "CreateParticipantCollection - exit S_OK"));
return S_OK;
}