|
|
/*++
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; }
|