/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: mspaddr.cpp Abstract: This module contains implementation of CMSPAddress. --*/ #include "precomp.h" #pragma hdrstop /////////////////////////////////////////////////////////////////////////////// // // AllocateEventItem and FreeEventItem are MSPEVENTITEM allocation routines. // they are be used to allocate and deallocate MSPEVENTITEM structures // /////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // AllocateEventItem // // allocate an MSPEVENTITEM. Since the structure is of variable size, the // number of extra bytes to be allocated (in addition to the size of // MSPEVENTITEM) is optionally passed as the function's argument // // the function returns a pointer to the newly created structure or NULL in // the case of failure. the caller can then call GetLastError to get more // information on the failure // MSPEVENTITEM *AllocateEventItem(SIZE_T nExtraBytes) { LOG((MSP_TRACE, "AllocateEventItem - enter, extra bytes = 0x%p", nExtraBytes)); // // if the caller passes us too big a number, fail. // if ( ( MAXULONG_PTR - sizeof(MSPEVENTITEM) ) < nExtraBytes ) { SetLastError(ERROR_OUTOFMEMORY); LOG((MSP_ERROR, "AllocateEventItem - the caller requested an unreasonably large memory block")); return NULL; } // // allocate on the process' heap. get the current process' heap handle. // HANDLE hHeapHandle = GetProcessHeap(); if (NULL == hHeapHandle) { // // failed to get process's heap. nothing much we can do here. // this will cause a leak. // LOG((MSP_ERROR, "AllocateEventItem - failed to get current process heap. LastError [%ld]", GetLastError())); return NULL; } // // calculate the number of bytes to allocate // SIZE_T nTotalAllocationSize = sizeof(MSPEVENTITEM) + nExtraBytes; // // attempt to allocate memory and return result of the allocation // MSPEVENTITEM *pMspEventItem = (MSPEVENTITEM *)HeapAlloc(hHeapHandle, 0, nTotalAllocationSize); if (NULL == pMspEventItem) { LOG((MSP_ERROR, "AllocateEventItem - failed to allocate [0x%p] bytes. Heap Handle [%p] LastError [%ld]", nTotalAllocationSize, hHeapHandle, GetLastError())); } else { LOG((MSP_TRACE, "AllocateEventItem - exit. pMspEventItem = [%p]", pMspEventItem)); } return pMspEventItem; } ////////////////////////////////////////////////////////////////////////////// // // FreeEventItem // // deallocate the MSPEVENTITEM passed as an argument. The memory must have // been previously allocated by AllocateEventItem. // // the function eturns FALSE in case of failure. The caller can use // GetLastError to get a more specific error code. // BOOL FreeEventItem(MSPEVENTITEM *pEventItemToBeFreed) { LOG((MSP_TRACE, "FreeEventItem - enter. pEventItemToBeFreed = [%p]", pEventItemToBeFreed)); // // always allow freeing NULL // if (NULL == pEventItemToBeFreed) { LOG((MSP_TRACE, "FreeEventItem - finish. NULL -- nothing to do")); return TRUE; } // // the event item should have been allocated on the process' heap. // get the current process' heap hadle. // HANDLE hHeapHandle = GetProcessHeap(); if (NULL == hHeapHandle) { // // failed to get process's heap. nothing much we can do here. // this will cause a leak. // LOG((MSP_ERROR, "FreeEventItem - failed to get current process heap. LastError = %ld", GetLastError())); return FALSE; } // // attempt to free memory and return result of the operation // BOOL bFreeSuccess = HeapFree( hHeapHandle, 0, pEventItemToBeFreed ); if (bFreeSuccess) { LOG((MSP_TRACE, "FreeEventItem - exit.")); } else { LOG((MSP_ERROR, "FreeEventItem - failed to free. Heap Handle [%p] LastError = %ld", hHeapHandle, GetLastError())); } return bFreeSuccess; } ////////////////////////////////////////////////////////////////////////////// HRESULT CPlugTerminalClassInfo::FinalConstruct(void) { LOG((MSP_TRACE, "CPlugTerminalClassInfo::FinalConstruct - enter")); HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(), & m_pFTM ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::FinalConstruct - " "create FTM returned 0x%08x; exit", hr)); return hr; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::FinalConstruct - exit S_OK")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_Name( /*[out, retval]*/ BSTR* pName ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Name - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pName, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -" "pName invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrName, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pName = SysAllocString( m_bstrName ); // // Validates SysAllocString // if( *pName == NULL ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Name - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_Name( /*[in]*/ BSTR bstrName ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Name - enter")); // // Validates argument // if(IsBadStringPtr( bstrName, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Name exit -" "bstrName invalid, returns E_POINTER")); return E_POINTER; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrName, (UINT)-1) ) { SysFreeString( m_bstrName ); m_bstrName = NULL; } // // Set the new name // m_bstrName = SysAllocString( bstrName ); // // Validates SysAllocString // if( NULL == m_bstrName ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Name exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Name - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_Company( /*[out, retval]*/ BSTR* pCompany ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Company - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pCompany, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -" "pCompany invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrCompany, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pCompany = SysAllocString( m_bstrCompany ); // // Validates SysAllocString // if( *pCompany == NULL ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Company - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_Company( /*[in]*/ BSTR bstrCompany ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Company - enter")); // // Validates argument // if(IsBadStringPtr( bstrCompany, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Company exit -" "bstrCompany invalid, returns E_POINTER")); return E_POINTER; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrCompany, (UINT)-1) ) { SysFreeString( m_bstrCompany ); m_bstrCompany = NULL; } // // Set the new name // m_bstrCompany = SysAllocString( bstrCompany ); // // Validates SysAllocString // if( NULL == m_bstrCompany ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Company exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Company - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_Version( /*[out, retval]*/ BSTR* pVersion ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Version - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pVersion, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -" "pVersion invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrVersion, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pVersion = SysAllocString( m_bstrVersion ); // // Validates SysAllocString // if( *pVersion == NULL ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Version - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_Version( /*[in]*/ BSTR bstrVersion ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Version - enter")); // // Validates argument // if(IsBadStringPtr( bstrVersion, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Version exit -" "bstrVersion invalid, returns E_POINTER")); return E_POINTER; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrVersion, (UINT)-1) ) { SysFreeString( m_bstrVersion ); m_bstrVersion = NULL; } // // Set the new name // m_bstrVersion = SysAllocString( bstrVersion ); // // Validates SysAllocString // if( NULL == m_bstrVersion ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Version exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Version - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_TerminalClass( /*[out, retval]*/ BSTR* pTerminalClass ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_TerminalClass - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pTerminalClass, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -" "pVersion invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrTerminalClass, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pTerminalClass = SysAllocString( m_bstrTerminalClass ); // // Validates SysAllocString // if( *pTerminalClass == NULL ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_TerminalClass - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_TerminalClass( /*[in]*/ BSTR bstrTerminalClass ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_TerminalClass - enter")); // // Validates argument // if(IsBadStringPtr( bstrTerminalClass, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -" "bstrTerminalClass invalid, returns E_POINTER")); return E_POINTER; } // // Is a real CLSID? // CLSID clsid; HRESULT hr = CLSIDFromString(bstrTerminalClass, &clsid); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -" "bstrTerminalClass is not a CLSID, returns E_INVALIDARG")); return E_INVALIDARG; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrTerminalClass, (UINT)-1) ) { SysFreeString( m_bstrTerminalClass ); m_bstrTerminalClass = NULL; } // // Set the new name // m_bstrTerminalClass = SysAllocString( bstrTerminalClass ); // // Validates SysAllocString // if( NULL == m_bstrTerminalClass ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_TerminalClass - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_CLSID( /*[out, retval]*/ BSTR* pCLSID ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_CLSID - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pCLSID, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -" "pVersion invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrCLSID, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pCLSID = SysAllocString( m_bstrCLSID ); // // Validates SysAllocString // if( *pCLSID == NULL ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_CLSID - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_CLSID( /*[in]*/ BSTR bstrCLSID ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_CLSID - enter")); // // Validates argument // if(IsBadStringPtr( bstrCLSID, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -" "bstrCLSID invalid, returns E_POINTER")); return E_POINTER; } // // Is a real CLSID? // CLSID clsid; HRESULT hr = CLSIDFromString(bstrCLSID, &clsid); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -" "bstrCLSID is not a CLSID, returns E_INVALIDARG")); return E_INVALIDARG; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrCLSID, (UINT)-1) ) { SysFreeString( m_bstrCLSID ); m_bstrCLSID = NULL; } // // Set the new name // m_bstrCLSID = SysAllocString( bstrCLSID ); // // Validates SysAllocString // if( NULL == m_bstrCLSID ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_CLSID - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_Direction( /*[out, retval]*/ TERMINAL_DIRECTION* pDirection ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Direction - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pDirection, sizeof(long)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Direction exit -" "pDirection invalid, returns E_POINTER")); return E_POINTER; } // // Return the name // *pDirection = m_Direction; LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Direction - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_Direction( /*[in]*/ TERMINAL_DIRECTION nDirection ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Direction - enter")); // // Set the new name // m_Direction = nDirection; LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Direction - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::get_MediaTypes( /*[out, retval]*/ long* pMediaTypes ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_MediaTypes - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pMediaTypes, sizeof(long)) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_MediaTypes exit -" "pMediaTypes invalid, returns E_POINTER")); return E_POINTER; } // // Return the name // *pMediaTypes = m_lMediaType; LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_MediaTypes - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalClassInfo::put_MediaTypes( /*[in]*/ long nMediaTypes ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_MediaTypes - enter")); // // Set the new name // m_lMediaType = nMediaTypes; LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_MediaTypes - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// HRESULT CPlugTerminalSuperclassInfo::FinalConstruct(void) { LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::FinalConstruct - enter")); HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(), & m_pFTM ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::FinalConstruct - " "create FTM returned 0x%08x; exit", hr)); return hr; } LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::FinalConstruct - exit S_OK")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalSuperclassInfo::get_Name( /*[out, retval]*/ BSTR* pName ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_Name - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pName, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -" "pVersion invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrName, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pName = SysAllocString( m_bstrName ); // // Validates SysAllocString // if( *pName == NULL ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_Name - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalSuperclassInfo::put_Name( /*[in]*/ BSTR bstrName ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Name - enter")); // // Validates argument // if(IsBadStringPtr( bstrName, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_Name exit -" "bstrName invalid, returns E_POINTER")); return E_POINTER; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrName, (UINT)-1) ) { SysFreeString( m_bstrName ); m_bstrName = NULL; } // // Set the new name // m_bstrName = SysAllocString( bstrName ); // // Validates SysAllocString // if( NULL == m_bstrName ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_Name exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Name - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalSuperclassInfo::get_CLSID( /*[out, retval]*/ BSTR* pCLSID ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_CLSID - enter")); // // Validates argument // if( MSPB_IsBadWritePtr( pCLSID, sizeof(BSTR)) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -" "pVersion invalid, returns E_POINTER")); return E_POINTER; } // // Validates the name // if( IsBadStringPtr( m_bstrCLSID, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -" "m_bstrName invalid, returns E_UNEXPECTED")); return E_UNEXPECTED; } // // Return the name // *pCLSID = SysAllocString( m_bstrCLSID ); // // Validates SysAllocString // if( *pCLSID == NULL ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_CLSID - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPlugTerminalSuperclassInfo::put_CLSID( /*[in]*/ BSTR bstrCLSID ) { // // Critical section // CLock lock(m_CritSect); LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_CLSID - enter")); // // Validates argument // if(IsBadStringPtr( bstrCLSID, (UINT)-1) ) { LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -" "bstrCLSID invalid, returns E_POINTER")); return E_POINTER; } // // Is a real CLSID? // CLSID clsid; HRESULT hr = CLSIDFromString(bstrCLSID, &clsid); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_CLSID exit -" "bstrCLSID is not a CLSID, returns E_INVALIDARG")); return E_INVALIDARG; } // // Clean-up the old name // if(!IsBadStringPtr( m_bstrCLSID, (UINT)-1) ) { SysFreeString( m_bstrCLSID ); m_bstrCLSID = NULL; } // // Set the new name // m_bstrCLSID = SysAllocString( bstrCLSID ); // // Validates SysAllocString // if( NULL == m_bstrCLSID ) { LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_CLSID exit -" "SysAllocString failed, returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_CLSID - exit")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// // // Our available static terminal types. // const STATIC_TERMINAL_TYPE CMSPAddress::m_saTerminalTypes[] = { { (DWORD) TAPIMEDIATYPE_AUDIO, &CLSID_CWaveinClassManager, CAudioCaptureTerminal::CreateTerminal }, { (DWORD) TAPIMEDIATYPE_AUDIO, &CLSID_CWaveOutClassManager, CAudioRenderTerminal::CreateTerminal }, { (DWORD) TAPIMEDIATYPE_VIDEO, &CLSID_CVidCapClassManager, CVideoCaptureTerminal::CreateTerminal } }; const DWORD CMSPAddress::m_sdwTerminalTypesCount = sizeof(m_saTerminalTypes) / sizeof (STATIC_TERMINAL_TYPE); ///////////////////////////////////////////////////////////////////////////// // CMSPAddress ///////////////////////////////////////////////////////////////////////////// // // Check to see if the mediatype is non-zero and is in the mask. // Your MSP can override this if it needs to do atypically complex // checks on specific combinations of media types (e.g., can never // have more than one media type on a call, can have video with audio // but not video alone, etc.). The default implementation accepts any // nonempty set of media types that is a subset of the set of types // in the mask. // BOOL CMSPAddress::IsValidSetOfMediaTypes(DWORD dwMediaType, DWORD dwMask) { return (dwMediaType != 0) && ((dwMediaType & dwMask) == dwMediaType); } CMSPAddress::CMSPAddress() : m_htEvent(NULL), m_fTerminalsUpToDate(FALSE), m_pITTerminalManager(NULL) { LOG((MSP_TRACE, "CMSPAddress::CMSPAddress[%p] - enter", this)); LOG((MSP_TRACE, "CMSPAddress::CMSPAddress - finished")); } CMSPAddress::~CMSPAddress() { LOG((MSP_TRACE, "CMSPAddress::~CMSPAddress[%p] - enter", this)); // // this should have been taken care of in Shutdown, // but just in case shutdown was never called, do this again, since // we need to make sure the thread does not have any stale entries in // its pnp notification list // // the call is likely to return error (since the object is likely to have been // unregisted earlier) -- so ignore return code // g_Thread.UnregisterPnpNotification(this); LOG((MSP_TRACE, "CMSPAddress::~CMSPAddress - finished")); } STDMETHODIMP CMSPAddress::Initialize( IN MSP_HANDLE htEvent ) /*++ Routine Description: This method is called by TAPI3 when this MSP is first created. The method initiailzes data members and creates the terminal manager. It also tells the global thread object to Start(). Arguments: htEvent Event the MSP signals when passing an event structure back to TAPI. Return Value: S_OK E_INVALIDARG E_OUTOFMEMORY TAPI_E_REGISTERCALLBACK --*/ { LOG((MSP_TRACE, "MSP address %x initialize entered, htEvent:%x", this, htEvent)); if ( htEvent == NULL ) { LOG((MSP_ERROR, " bad handle: htEvent:%x", htEvent)); return E_INVALIDARG; } // lock the event related data m_EventDataLock.Lock(); if (m_htEvent != NULL) { m_EventDataLock.Unlock(); LOG((MSP_ERROR, "Initialze called twice.")); return E_UNEXPECTED; } // save handles. m_htEvent = htEvent; InitializeListHead(&m_EventList); HRESULT hr; // release the lock on the event related data m_EventDataLock.Unlock(); // lock the terminal related data. This is a auto lock that will unlock // when the function returns. CLock lock(m_TerminalDataLock); // Create the terminal manager. hr = CoCreateInstance( CLSID_TerminalManager, NULL, CLSCTX_INPROC_SERVER, IID_ITTerminalManager, (void **) &m_pITTerminalManager ); if (FAILED(hr)) { LOG((MSP_ERROR, "Creating terminal manager failed. return: %x", hr)); return hr; } hr = g_Thread.Start(); if (FAILED(hr)) { m_pITTerminalManager->Release(); m_pITTerminalManager = NULL; LOG((MSP_ERROR, "Creating thread failed. return: %x", hr)); return hr; } hr = g_Thread.RegisterPnpNotification(this); if (FAILED(hr)) { LOG((MSP_ERROR, "Unable to register for PNP notification. return: %x", hr)); } LOG((MSP_TRACE, "MSP address %x initialize exited S_OK, htEvent:%x", this, htEvent)); return S_OK; } STDMETHODIMP CMSPAddress::Shutdown () /*++ Routine Description: This method is called by TAPI3 when this address in not in use any more. This function releases the terminals and releases the terminal manager. It releases all unprocessed events, and also stops the worker thread. When this functions is called, no call should be alive. However, bugs in the app may keep calls or terminals around. Currently this function does not attempt to solve this problem. The calls will have their own refcounts on the terminals, so it shouldn't fail anyway. Arguments: None. Return Value: S_OK --*/ { LOG((MSP_TRACE, "CMSPAddress::Shutdown - " "MSP address %x is shutting down", this)); HRESULT hr; // // Unregister for PNP notification // hr = g_Thread.UnregisterPnpNotification(this); if (FAILED(hr)) { LOG((MSP_ERROR, "Unable to unregister for PNP notification. return: %x", hr)); } // // Tell the worker thread to stop. // g_Thread.Stop(); LOG((MSP_INFO, "CMSPAddress::Shutdown - thread has stopped")); // acquire the lock on the terminal data because we are writing to it. m_TerminalDataLock.Lock(); // Release the terminal manager. if (m_pITTerminalManager != NULL) { m_pITTerminalManager->Release(); m_pITTerminalManager = NULL; } // release all the terminals. for (int i = 0; i < m_Terminals.GetSize(); i ++) { // // Clear its CMSPAddress pointer // CBaseTerminal * pCTerminal = static_cast (m_Terminals[i]); m_Terminals[i]->Release(); } m_Terminals.RemoveAll(); // We are done with terminal related data, release the lock. m_TerminalDataLock.Unlock(); LOG((MSP_INFO, "CMSPAddress::Shutdown - terminals released")); // acquire the lock on the event data because we are writing to it. m_EventDataLock.Lock(); m_htEvent = NULL; // release all the unprocessed events in the list. while (!IsListEmpty(&m_EventList)) { // retrieve first entry PLIST_ENTRY pLE = RemoveHeadList(&m_EventList); // convert list entry to structure pointer PMSPEVENTITEM pItem = CONTAINING_RECORD(pLE, MSPEVENTITEM, Link); // release the refcount in the event. LOG((MSP_INFO, "CMSPAddress::Shutdown:releasing event still in the queue: %x", pItem->MSPEventInfo.Event )); switch (pItem->MSPEventInfo.Event) { case ME_ADDRESS_EVENT: if (pItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal) { pItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal->Release(); } break; case ME_CALL_EVENT: if (pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream) { pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream->Release(); } if (pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal) { pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal->Release(); } break; case ME_PRIVATE_EVENT: if (pItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent) { pItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent->Release(); } break; case ME_TSP_DATA: // nothing inside the structure that we need to free break; case ME_FILE_TERMINAL_EVENT: if( NULL != pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal) { (pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal)->Release(); pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal = NULL; } if( NULL != pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack ) { (pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack)->Release(); pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack = NULL; } break; case ME_ASR_TERMINAL_EVENT: if( NULL != pItem->MSPEventInfo.MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal) { (pItem->MSPEventInfo.MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal)->Release(); } break; case ME_TTS_TERMINAL_EVENT: if( NULL != pItem->MSPEventInfo.MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal) { (pItem->MSPEventInfo.MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal)->Release(); } break; case ME_TONE_TERMINAL_EVENT: if( NULL != pItem->MSPEventInfo.MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal) { (pItem->MSPEventInfo.MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal)->Release(); } break; default: LOG((MSP_WARN, "CMSPAddress::Shutdown: unknown event type: %x", pItem->MSPEventInfo.Event)); break; } FreeEventItem(pItem); } // We are done with event related data, release the lcok. m_EventDataLock.Unlock(); LOG((MSP_TRACE, "CMSPAddress::Shutdown - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::ReceiveTSPData( IN IUnknown * pMSPCall, IN LPBYTE pBuffer, IN DWORD dwBufferSize ) /*++ Routine Description: This method is called by TAPI3 when the TSP address sends data to this MSP address object. The semantics of the data passed in the buffer are specific to each TSP - MSP pair. This method dispatches the received buffer to the address (call == NULL) or call (call != NULL). Arguments: pMSPCall The call object that the data is for. If it is NULL, the data is for this address. pBuffer Opaque buffer from TSP. dwBufferSize Size in bytes of pBuffer Return Value: S_OK --*/ { LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData entered. pMSPCall:%x", pMSPCall)); _ASSERTE(dwBufferSize > 0); _ASSERTE(!IsBadReadPtr(pBuffer, sizeof(BYTE) * (dwBufferSize) ) ); HRESULT hr; if ( NULL == pMSPCall ) { hr = ReceiveTSPAddressData(pBuffer, dwBufferSize); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - " "ReceiveTSPAddressData failed - exit 0x%08x", hr)); return hr; } LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData - " "exit S_OK (dispatched to address)")); return S_OK; } // // We have a call to dispatch to. // _ASSERTE(!IsBadReadPtr(pMSPCall, sizeof(IUnknown) ) ); ITStreamControl * pIStreamControl; hr = pMSPCall->QueryInterface(IID_ITStreamControl, (void **)&pIStreamControl); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - " "can't get the ITStream Control interface - exit 0x%08x", hr)); return hr; } CMSPCallBase * pCall = static_cast (pIStreamControl); if (pCall == NULL) { LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - " "invalid msp call pointer: %x", pMSPCall)); pIStreamControl->Release(); return E_UNEXPECTED; } hr = pCall->ReceiveTSPCallData(pBuffer, dwBufferSize); pIStreamControl->Release(); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - " "method on call failed - exit 0x%08x", hr)); return hr; } LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData - " "exit S_OK (dispatched to call)")); return S_OK; } HRESULT CMSPAddress::GetStaticTerminals( IN OUT DWORD * pdwNumTerminals, OUT ITTerminal ** ppTerminals ) /*++ Routine Description: This method is called by TAPI3 to get a list of static terminals that can be used on this address. If our list is not empty, just return the list. If our list is still empty, create the static terminals and return the list. Derived class can override this method to have their own terminals. Locks the terminal lists. Arguments: pdwNumTerminals Pointer to a DWORD. On entry, indicates the size of the buffer pointed to in ppTerminals. On success, it will be filled in with the actual number of terminals returned. If the buffer is not big enough, the method will return TAPI_E_NOTENOUGHMEMORY, and it will be filled in the with number of terminals needed. ppTerminals On success, filled in with an array of terminals object pointers that are supported by the MSP for this address. This value may be NULL, in which case pdwNumTerminals will return the needed buffer size. Return Value: S_OK E_OUTOFMEMORY TAPI_E_NOTENOUGHMEMORY --*/ { LOG((MSP_TRACE, "GetStaticTerminals entered. NumTerminals:%x, ppTerminals:%x", *pdwNumTerminals, ppTerminals )); // lock the terminal related data. This is a auto lock that will unlock // when the function returns. CLock lock(m_TerminalDataLock); if (!m_fTerminalsUpToDate) { HRESULT hr = UpdateTerminalList(); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - " "UpdateTerminalList failed - returning 0x%08x", hr)); return hr; } } // // Check if initialized. // if ( m_htEvent == NULL ) { LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - " "not initialized - returning E_UNEXPECTED")); return E_UNEXPECTED; } // // Check parameters. // if ( MSPB_IsBadWritePtr(pdwNumTerminals, sizeof(DWORD) ) ) { LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - " "bad pdwNumTerminals pointer - exit E_POINTER")); return E_POINTER; } if ( ppTerminals != NULL ) { if ( MSPB_IsBadWritePtr(ppTerminals, *pdwNumTerminals * sizeof(ITTerminal *) ) ) { LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - " "bad ppTerminals pointer - exit E_POINTER")); return E_POINTER; } } // // Grab the size of the terminals list. // int iSize = m_Terminals.GetSize(); _ASSERTE( iSize >= 0 ); // // Add our terminals to the output list if the caller wants an output // list, and provided there is enough room in the output list. // if ( ( ppTerminals != NULL ) && ( (DWORD) iSize <= *pdwNumTerminals ) ) { // // For each terminal in the list of terminals we created, // AddRef and copy the terminal pointer. // for (int i = 0; i < iSize; i++) { m_Terminals[i]->AddRef(); ppTerminals[i] = m_Terminals[i]; } } // // If there was no output list then we just have to report the number // of terminals available. // if ( ppTerminals == NULL ) { *pdwNumTerminals = (DWORD) iSize; LOG((MSP_TRACE, "CMSPAddress::GetStaticTerminals - just returned number of " "terminals available - exit S_OK")); return S_OK; } // // If there was an output list but it was not large enough, then // return the appropriate error. // if ( (DWORD) iSize > *pdwNumTerminals ) { *pdwNumTerminals = (DWORD) iSize; LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - passed-in array not " "large enough - exit TAPI_E_NOTENOUGHMEMORY")); return TAPI_E_NOTENOUGHMEMORY; } // // Otherwise, everything was fine. We just need to report the actual // number of terminals we copied and return S_OK. // *pdwNumTerminals = (DWORD) iSize; LOG((MSP_TRACE, "CMSPAddress::GetStaticTerminals - " "returned terminals - exit S_OK")); return S_OK; } HRESULT CMSPAddress::IsMonikerInTerminalList(IMoniker* pMoniker) { CSingleFilterStaticTerminal *pCSingleFilterStaticTerminal; // // Grab the size of the terminals list. // int iSize = m_Terminals.GetSize(); _ASSERTE( iSize >= 0 ); // // Add our terminals to the output list if the caller wants an output // list, and provided there is enough room in the output list. // for (int i = 0; i < iSize; i++) { pCSingleFilterStaticTerminal = static_cast(m_Terminals[i]); if ( pCSingleFilterStaticTerminal->CompareMoniker( pMoniker ) == S_OK ) { LOG((MSP_TRACE, "CMSPAddress::IsMonikerInTerminalList - " "moniker found in terminal list")); pCSingleFilterStaticTerminal->m_bMark = TRUE; // mark this terminal so we don't remove it return S_OK; } } LOG((MSP_TRACE, "CMSPAddress::IsMonikerInTerminalList - " "moniker not found in terminal list")); return S_FALSE; } HRESULT CMSPAddress::UpdateTerminalListForPnp( IN BOOL bDeviceArrival ) { CSingleFilterStaticTerminal *pCSingleFilterStaticTerminal; // // Clear all marks in the terminal list // int iSize = m_Terminals.GetSize(); _ASSERTE( iSize >= 0 ); for (int i = 0; i < iSize; i++) { pCSingleFilterStaticTerminal = static_cast(m_Terminals[i]); if (pCSingleFilterStaticTerminal == NULL) { LOG((MSP_ERROR, "CMSPAddress::IsMonikerInTerminalList - " "bad terminal pointer")); return E_FAIL; } pCSingleFilterStaticTerminal->m_bMark = FALSE; } // // Create DevEnum, which is the DirectShow Category Enumerator Creator // HRESULT hr; ICreateDevEnum * pCreateDevEnum; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp " "can't CoCreate DevEnum - returning 0x%08x", hr)); return hr; } IEnumMoniker * pCatEnum; for ( i = 0; i < m_sdwTerminalTypesCount; i++ ) { // // Skip any terminal types that don't use one of the supported media // modes. // if ( ! IsValidSingleMediaType( m_saTerminalTypes[i].dwMediaType, GetCallMediaTypes() ) ) { continue; } // // Create the actual category enumerator. // hr = pCreateDevEnum->CreateClassEnumerator( *(m_saTerminalTypes[i].clsidClassManager), &pCatEnum, 0); if ( hr != S_OK ) // S_FALSE means the category does not exist! { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp " "can't create class enumerator - returning 0x%08x", hr)); continue; } IMoniker * pMoniker; while ((hr = pCatEnum->Next(1, &pMoniker, NULL)) == S_OK) { if (IsMonikerInTerminalList(pMoniker) == S_FALSE) { // // Create a terminal and give it its moniker. // ITTerminal * pTerminal; hr = (m_saTerminalTypes[i].pfnCreateTerm)(pMoniker, (MSP_HANDLE) this, &pTerminal); // // The terminal keeps a reference to the moniker if it needs to. // pMoniker->Release(); if (SUCCEEDED(hr)) { // // Add this terminal pointer to our list. Don't release it; we // keep this one reference to it in the list. // BOOL fSuccess = m_Terminals.Add(pTerminal); if ( ! fSuccess ) { pCatEnum->Release(); pTerminal->Release(); LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "can't add terminal to list; returning E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Set its CMSPAddress pointer // CBaseTerminal * pCTerminal = static_cast (pTerminal); // // Mark this terminal so we don't remove it // pCSingleFilterStaticTerminal = static_cast(pTerminal); if (pCSingleFilterStaticTerminal == NULL) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "bad terminal pointer")); return E_FAIL; } pCSingleFilterStaticTerminal->m_bMark = TRUE; // // Post a TAPI message about the new terminal's arrival // pTerminal->AddRef(); MSPEVENTITEM *pEventItem; pEventItem = AllocateEventItem(); if (pEventItem == NULL) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "can't allocate event item; returning E_OUTOFMEMORY")); pTerminal->Release(); return E_OUTOFMEMORY; } pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO); pEventItem->MSPEventInfo.Event = ME_ADDRESS_EVENT; pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_AVAILABLE; pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = pTerminal; hr = PostEvent(pEventItem); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "post event failed")); pTerminal->Release(); FreeEventItem(pEventItem); } } } // // If it failed, that either means we skipped the device because it // was unsuitable (a routine occurance) or something failed, like // out of memory. I should come up with a way to differentiate and // handle this well. // } // // We are done with the enumerator. // pCatEnum->Release(); } // // Release DevEnum. // pCreateDevEnum->Release(); // // Sweep the terminal list and clean up any terminals which are no longer present // iSize = m_Terminals.GetSize(); _ASSERTE( iSize >= 0 ); for (i = 0; i < iSize; i++) { pCSingleFilterStaticTerminal = static_cast(m_Terminals[i]); if (pCSingleFilterStaticTerminal == NULL) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "bad terminal pointer")); return E_FAIL; } if (!pCSingleFilterStaticTerminal->m_bMark) { // // This terminal has is no longer present, lets remove it from the list // LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalListForPnp " "found a terminal to be removed")); ITTerminal * pTerminal = m_Terminals[i]; if (m_Terminals.RemoveAt(i)) { // // Clear its CMSPAddress pointer // CBaseTerminal * pCTerminal = static_cast (pTerminal); // // We don't release the terminal here even though we are removing // it from the terminal list because TAPI3.dll will release it // when it releases the event. // // // Post a TAPI message about the new terminal's removal // MSPEVENTITEM *pEventItem; pEventItem = AllocateEventItem(); if (pEventItem == NULL) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "can't allocate event item; returning E_OUTOFMEMORY")); pTerminal->Release(); return E_OUTOFMEMORY; } pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO); pEventItem->MSPEventInfo.Event = ME_ADDRESS_EVENT; pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_UNAVAILABLE; pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = pTerminal; hr = PostEvent(pEventItem); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - " "post event failed")); pTerminal->Release(); FreeEventItem(pEventItem); } // // fix up our search indices to account for a removal // iSize--; i--; } } } // // Our list is now complete. // m_fTerminalsUpToDate = TRUE; LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalListForPnp - exit S_OK")); return S_OK; } HRESULT CMSPAddress::UpdateTerminalList(void) { // // Create DevEnum, which is the DirectShow Category Enumerator Creator // HRESULT hr; ICreateDevEnum * pCreateDevEnum; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList " "can't CoCreate DevEnum - returning 0x%08x", hr)); return hr; } IEnumMoniker * pCatEnum; for ( DWORD i = 0; i < m_sdwTerminalTypesCount; i++ ) { // // Skip any terminal types that don't use one of the supported media // modes. // if ( ! IsValidSingleMediaType( m_saTerminalTypes[i].dwMediaType, GetCallMediaTypes() ) ) { continue; } // // Create the actual category enumerator. // hr = pCreateDevEnum->CreateClassEnumerator( *(m_saTerminalTypes[i].clsidClassManager), &pCatEnum, 0); if ( hr != S_OK ) // S_FALSE means the category does not exist! { LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList " "can't create class enumerator - returning 0x%08x", hr)); continue; } IMoniker * pMoniker; while ((hr = pCatEnum->Next(1, &pMoniker, NULL)) == S_OK) { // // Create a terminal and give it its moniker. // ITTerminal * pTerminal; hr = (m_saTerminalTypes[i].pfnCreateTerm)(pMoniker, (MSP_HANDLE) this, &pTerminal); // // The terminal keeps a reference to the moniker if it needs to. // pMoniker->Release(); if (SUCCEEDED(hr)) { // // Add this terminal pointer to our list. Don't release it; we // keep this one reference to it in the list. // BOOL fSuccess = m_Terminals.Add(pTerminal); if ( ! fSuccess ) { pCatEnum->Release(); LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList - " "can't add terminal to list; returning E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Set its CMSPAddress pointer // CBaseTerminal * pCTerminal = static_cast (pTerminal); } // // If it failed, that either means we skipped the device because it // was unsuitable (a routine occurance) or something failed, like // out of memory. I should come up with a way to differentiate and // handle this well. // } // // We are done with the enumerator. // pCatEnum->Release(); } // // Release DevEnum. // pCreateDevEnum->Release(); // // Our list is now complete. // m_fTerminalsUpToDate = TRUE; LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalList - exit S_OK")); return S_OK; } HRESULT CMSPAddress::GetDynamicTerminalClasses( IN OUT DWORD * pdwNumClasses, OUT IID * pTerminalClasses ) /*++ Routine Description: This method is called by TAPI3 to get a list of dynamic terminal guids that can be used on this address. It asks the terminal manager for the list of guids and returns them. Derived class can override this method to have their own guids. Arguments: pdwNumClasses Pointer to a DWORD. On entry, indicates the size of the buffer pointed to in pTerminalClasses. On success, it will be filled in with the actual number of class IIDs returned. If the buffer is not big enough, the method will return TAPI_E_NOTENOUGHMEMORY, and it will be filled in the with number of IIDs needed. pTerminalClasses On success, filled in with an array of terminal class IIDs that are supported by the MSP for this address. This value may be NULL, in which case pdwNumClasses will return the needed buffer size. Return Value: S_OK E_OUTOFMEMORY TAPI_E_NOTENOUGHMEMORY --*/ { LOG((MSP_TRACE, "CMSPAddress::GetDynamicTerminalClasses - enter")); // // Check if initialized. // // lock the event related data m_EventDataLock.Lock(); if ( m_htEvent == NULL ) { // unlock the event related data m_EventDataLock.Unlock(); LOG((MSP_ERROR, "CMSPAddress::GetDynamicTerminalClasses - " "not initialized - returning E_UNEXPECTED")); return E_UNEXPECTED; } // unlock the event related data m_EventDataLock.Unlock(); // // Ask the Terminal Manager for the dynamic terminals that apply to // all of our supported media types. Since the mapping is // direct, the Terminal Manager takes care of all argument checking. // HRESULT hr; hr = m_pITTerminalManager->GetDynamicTerminalClasses( GetCallMediaTypes(), pdwNumClasses, pTerminalClasses); LOG((MSP_TRACE, "CMSPAddress::GetDynamicTerminalClasses - exit 0x%08x", hr)); return hr; } STDMETHODIMP CMSPAddress::CreateTerminal( IN BSTR pTerminalClass, IN long lMediaType, IN TERMINAL_DIRECTION Direction, OUT ITTerminal ** ppTerminal ) /*++ Routine Description: This method is called by TAPI3 to create a dynamic terminal. It asks the terminal manager to create a dynamic terminal. Derived class can override this method to have their own way of creating a dynamic terminal. Arguments: iidTerminalClass IID of the terminal class to be created. dwMediaType TAPI media type of the terminal to be created. Direction Terminal direction of the terminal to be created. ppTerminal Returned created terminal object Return Value: S_OK E_OUTOFMEMORY TAPI_E_INVALIDMEDIATYPE TAPI_E_INVALIDTERMINALDIRECTION TAPI_E_INVALIDTERMINALCLASS --*/ { LOG((MSP_TRACE, "CMSPAddress::CreateTerminal - enter")); // // Check if initialized. // // lock the event related data m_EventDataLock.Lock(); if ( m_htEvent == NULL ) { // unlock the event related data m_EventDataLock.Unlock(); LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - " "not initialized - returning E_UNEXPECTED")); return E_UNEXPECTED; } // unlock the event related data m_EventDataLock.Unlock(); // // Get the IID from the BSTR representation. // HRESULT hr; IID iidTerminalClass; hr = CLSIDFromString(pTerminalClass, &iidTerminalClass); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - " "bad CLSID string - returning E_INVALIDARG")); return E_INVALIDARG; } // // Make sure we support the requested media type. // The terminal manager checks the terminal class, terminal direction, // and return pointer. // // // requested media type may be aggregated, but it must still be valid // if ( !IsValidAggregatedMediaType(lMediaType) ) { LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - " "unrecognized media type requested - returning E_INVALIDARG")); return E_INVALIDARG; } // // Use the terminal manager to create the dynamic terminal. // _ASSERTE( m_pITTerminalManager != NULL ); hr = m_pITTerminalManager->CreateDynamicTerminal(NULL, iidTerminalClass, (DWORD) lMediaType, Direction, (MSP_HANDLE) this, ppTerminal); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - " "create dynamic terminal failed - returning 0x%08x", hr)); return hr; } LOG((MSP_TRACE, "CMSPAddress::CreateTerminal - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::GetDefaultStaticTerminal( IN long lMediaType, IN TERMINAL_DIRECTION Direction, OUT ITTerminal ** ppTerminal ) /*++ Routine Description: This method is called by TAPI3 to get the default static terminal for a certain type and direction. It updates the list if needed, then figures out which terminal is the first of the appropriate type in our list. Derived classes can override this method to have their own way of deciding which terminal is the default. Locks the terminal lists. Arguments: dwMediaType The TAPIMEDIATYPE of the terminal to retrieve. Only one bit will be set. Direction TERMINAL_DIRECTION of the terminal to retrieve. ppTerminal Default terminal returned Return Value: S_OK E_POINTER E_OUTOFMEMORY TAPI_E_NOTSUPPORTED TAPI_E_INVALIDMEDIATYPE TAPI_E_INVALIDTERMINALDIRECTION --*/ { LOG((MSP_TRACE, "CMSPAddress::GetDefaultStaticTerminal - enter")); // // Check if initialized. // // lock the event related data m_EventDataLock.Lock(); if ( m_htEvent == NULL ) { // unlock the event related data m_EventDataLock.Unlock(); LOG((MSP_ERROR, "CMSPAddress::GetDefaultStaticTerminal - " "not initialized - returning E_UNEXPECTED")); return E_UNEXPECTED; } // unlock the event related data m_EventDataLock.Unlock(); // // Make sure we support this media type. // if ( ! IsValidSingleMediaType( (DWORD) lMediaType, GetCallMediaTypes() ) ) { LOG((MSP_ERROR, "CMSPAddress::GetDefaultStaticTerminal - " "non-audio terminal requested - returning E_INVALIDARG")); return E_INVALIDARG; } // // Check the direction. // if ( ( Direction != TD_CAPTURE ) && ( Direction != TD_RENDER ) ) { LOG((MSP_ERROR, "CMSPAddress::GetDefaultStaticTerminal - " "invalid direction - returning E_INVALIDARG")); return E_INVALIDARG; } // // Check return pointer. // if ( MSPB_IsBadWritePtr(ppTerminal, sizeof(ITTerminal *) ) ) { LOG((MSP_ERROR, "CMSPAddress::GetDefaultStaticTerminal - " "bad terminal return pointer - returning E_POINTER")); return E_POINTER; } // lock the terminal related data. This is a auto lock that will unlock // when the function returns. CLock lock(m_TerminalDataLock); if (!m_fTerminalsUpToDate) { HRESULT hr = UpdateTerminalList(); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::GetDefaultStaticTerminal - " "UpdateTerminalList failed - returning 0x%08x", hr)); return hr; } } // // For each terminal in the list of terminals we created... // int iSize = m_Terminals.GetSize(); for (int i = 0; i < iSize; i++) { ITTerminal * pTerminal = m_Terminals[i]; HRESULT hr; // // Make sure this is the right direction. // TERMINAL_DIRECTION dir; hr = pTerminal->get_Direction(&dir); if (FAILED(hr)) { LOG((MSP_WARN, "CMSPAddress::GetDefaultStaticTerminal - " "could not get terminal direction - skipping")); continue; } if ( dir != Direction ) { continue; } // // Make sure this is the right media type. // long lMediaTypeObserved; hr = pTerminal->get_MediaType(&lMediaTypeObserved); if (FAILED(hr)) { LOG((MSP_WARN, "CMSPAddress::GetDefaultStaticTerminal - " "could not get terminal media type - skipping")); continue; } if ( ( lMediaTypeObserved & lMediaType) == 0 ) { continue; } // // Ok, so this is the terminal we want. Addref it and give it to the // caller. // pTerminal->AddRef(); *ppTerminal = pTerminal; LOG((MSP_TRACE, "CMSPAddress::GetDefaultStaticTerminal - " "returned a terminal - exit S_OK")); return S_OK; } // // If we get here then we did not find any matching terminals. // LOG((MSP_TRACE, "CMSPAddress::GetDefaultStaticTerminal - " "no match - exit TAPI_E_NOITEMS")); return TAPI_E_NOITEMS; } STDMETHODIMP CMSPAddress::get_PluggableSuperclasses( OUT VARIANT * pVariant ) { LOG((MSP_TRACE, "CMSPAddress::get_PluggableSuperclasses - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } // // Get ITTemrinalManager2 // ITTerminalManager2* pTermMgr2 = NULL; HRESULT hr = E_FAIL; hr = m_pITTerminalManager->QueryInterface( IID_ITTerminalManager2, (void**)&pTermMgr2); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "QI for ITTerminalManager2 failed - returning 0x%08x", hr)); return hr; } // // Create the collection object - see mspcoll.h // typedef CTapiIfCollection< ITPluggableTerminalSuperclassInfo* > SuperclassCollection; CComObject * pCollection; hr = CComObject::CreateInstance( &pCollection ); if ( FAILED(hr) ) { //Clean-up pTermMgr2->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "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) ) { //Clean-up pTermMgr2->Release(); delete pCollection; LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "QI for IDispatch on collection failed - exit 0x%08x", hr)); return hr; } // // Find out how many superclasses are available. // DWORD dwNumSuperclasses = 0; hr = pTermMgr2->GetPluggableSuperclasses( &dwNumSuperclasses, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "can't get number of terminals - exit 0x%08x", hr)); //Clean-up pTermMgr2->Release(); pDispatch->Release(); return hr; } // // Allocate an array of IID. // IID* pSuperclassesIID = new IID[dwNumSuperclasses]; if ( pSuperclassesIID == NULL ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "can't allocate IIDs array - exit E_OUTOFMEMORY")); //Clean-up pTermMgr2->Release(); pDispatch->Release(); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = pTermMgr2->GetPluggableSuperclasses( &dwNumSuperclasses, pSuperclassesIID ); // // Clean-up // pTermMgr2->Release(); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "can't get IIDs - exit 0x%08x", hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; return hr; } // // Allocate an array of ITPluggableTerminalSuperclassInfo // typedef ITPluggableTerminalSuperclassInfo* SuperclassPtr; // MS parser SuperclassPtr * ppSuperclassesInfo = new SuperclassPtr[dwNumSuperclasses]; if ( ppSuperclassesInfo == NULL ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "can't allocate SuperclassPtr array - exit E_OUTOFMEMORY")); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; return E_OUTOFMEMORY; } // // Get ITPluggableTerminalSuperclassRegistration interface // ITPluggableTerminalSuperclassRegistration* pSuperclassReg = NULL; hr = CoCreateInstance( CLSID_PluggableSuperclassRegistration, NULL, CLSCTX_INPROC_SERVER, IID_ITPluggableTerminalSuperclassRegistration, (void**)&pSuperclassReg ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "QI for ITPluggableTerminalSuperclassRegistration - exit 0x%08x",hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; return hr; } // // Create the objects // for(DWORD dwIndex = 0; dwIndex < dwNumSuperclasses; dwIndex++) { // // Get the string from the IID // LPOLESTR lpszCLSID = NULL; hr = StringFromIID( pSuperclassesIID[dwIndex], &lpszCLSID); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "StringFromIID failed - exit 0x%08x",hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); return hr; } // // Get BSTR for IID // BSTR bstrCLSID = SysAllocString( lpszCLSID ); CoTaskMemFree( lpszCLSID ); // Clean-up if( NULL == bstrCLSID) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "SysAllocString failed - exit E_OUTOFMEMORY")); // Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); return E_OUTOFMEMORY; } // // Read information from registry // hr = pSuperclassReg->put_CLSID( bstrCLSID); if(FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "put_CLSID failed - exit 0x%08x",hr)); // Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID); return hr; } hr = pSuperclassReg->GetTerminalSuperclassInfo(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "GetTerminalSuperclassInfo failed - exit 0x%08x",hr)); // Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID); return hr; } // // Get the name // BSTR bstrName = NULL; pSuperclassReg->get_Name( &bstrName ); // // Create the information object // CComObject* pSuperclassInfo = NULL; hr = CComObject::CreateInstance(&pSuperclassInfo); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "CreateInstance failed - exit 0x%08x", hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } // // Get ITPluggableTerminalSuperclassInfo from this superclass // hr = pSuperclassInfo->QueryInterface( IID_ITPluggableTerminalSuperclassInfo, (void**)&ppSuperclassesInfo[dwIndex] ); _ASSERTE(hr == S_OK); // // Set the fields // hr = pSuperclassInfo->put_Name( bstrName); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "put_Name failed - exit 0x%08x", hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } hr = pSuperclassInfo->put_CLSID( bstrCLSID ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - " "put_CLSID failed - exit 0x%08x", hr)); //Clean-up pDispatch->Release(); delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } // // Clean-up // SysFreeString( bstrCLSID ); SysFreeString( bstrName ); } // // Clean-up the IIDs array // pSuperclassReg->Release(); delete[] pSuperclassesIID; // // Init the collection using an iterator -- pointers to the beginning and // the ending element plus one. If it succeeds, this method addrefs each // element of ppterminals by querying for IDispatch. // hr = pCollection->Initialize( dwNumSuperclasses, ppSuperclassesInfo, ppSuperclassesInfo + dwNumSuperclasses ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - exit " "pCollection->Initialize failed. returns 0x%08x", hr)); delete[] ppSuperclassesInfo; pDispatch->Release(); return hr; } // // put the IDispatch interface pointer into the variant // LOG((MSP_INFO, "CMSPAddress::get_PluggableSuperclasses - " "placing IDispatch value %08x in variant", pDispatch)); VariantInit(pVariant); pVariant->vt = VT_DISPATCH; pVariant->pdispVal = pDispatch; LOG((MSP_TRACE, "CMSPAddress::get_PluggableSuperclasses - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::EnumeratePluggableSuperclasses( OUT IEnumPluggableSuperclassInfo** ppSuperclassEnumerator ) { LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableSuperclasses - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(ppSuperclassEnumerator, sizeof(IEnumPluggableTerminalClassInfo*) ) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } // // Get ITTemrinalManager2 // ITTerminalManager2* pTermMgr2 = NULL; HRESULT hr = E_FAIL; hr = m_pITTerminalManager->QueryInterface( IID_ITTerminalManager2, (void**)&pTermMgr2); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "QI for ITTerminalManager2 failed - returning 0x%08x", hr)); return hr; } // // Find out how many superclasses are available. // DWORD dwNumSuperclasses = 0; hr = pTermMgr2->GetPluggableSuperclasses( &dwNumSuperclasses, NULL); if ( FAILED(hr) ) { // Clean-up pTermMgr2->Release(); LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't get number of terminals - exit 0x%08x", hr)); return hr; } // // Allocate an array of IID. // IID* pSuperclassesIID = new IID[dwNumSuperclasses]; if ( pSuperclassesIID == NULL ) { // Clean-up pTermMgr2->Release(); LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't allocate IIDs array - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = pTermMgr2->GetPluggableSuperclasses( &dwNumSuperclasses, pSuperclassesIID ); // // Clean-up // pTermMgr2->Release(); if ( FAILED(hr) ) { //Clean-up delete[] pSuperclassesIID; LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't get IIDs - exit 0x%08x", hr)); return hr; } // // Allocate an array of ITPluggableTerminalSuperclassInfo // typedef ITPluggableTerminalSuperclassInfo* SuperclassPtr; // MS parser SuperclassPtr * ppSuperclassesInfo = new SuperclassPtr[dwNumSuperclasses]; if ( ppSuperclassesInfo == NULL ) { // Clean-up delete[] pSuperclassesIID; LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't allocate SuperclassPtr array - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Get ITPluggableTerminalSuperclassRegistration interface // ITPluggableTerminalSuperclassRegistration* pSuperclassReg = NULL; hr = CoCreateInstance( CLSID_PluggableSuperclassRegistration, NULL, CLSCTX_INPROC_SERVER, IID_ITPluggableTerminalSuperclassRegistration, (void**)&pSuperclassReg ); if( FAILED(hr) ) { // Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "QI for ITPluggableTerminalSuperclassRegistration - exit 0x%08x",hr)); return hr; } // // Create the objects // for(DWORD dwIndex = 0; dwIndex < dwNumSuperclasses; dwIndex++) { // // Get the string from the IID // LPOLESTR lpszCLSID = NULL; hr = StringFromIID( pSuperclassesIID[dwIndex], &lpszCLSID); if( FAILED(hr) ) { //Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "StringFromIID failed - exit 0x%08x",hr)); return hr; } // // Get BSTR for IID // BSTR bstrCLSID = SysAllocString( lpszCLSID ); CoTaskMemFree( lpszCLSID ); // Clean-up if( NULL == bstrCLSID) { //Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "SysAllocString failed - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Read information from registry // pSuperclassReg->put_CLSID( bstrCLSID); hr = pSuperclassReg->GetTerminalSuperclassInfo(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "GetTerminalSuperclassInfo failed - exit 0x%08x",hr)); // Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID); return hr; } // // Get the name // BSTR bstrName = NULL; pSuperclassReg->get_Name( &bstrName ); // // Create the information object // CComObject* pSuperclassInfo = NULL; hr = CComObject::CreateInstance(&pSuperclassInfo); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "CreateInstance failed - exit 0x%08x", hr)); // Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } // // Get ITPluggableTerminalSuperclassInfo from this superclass // hr = pSuperclassInfo->QueryInterface( IID_ITPluggableTerminalSuperclassInfo, (void**)&ppSuperclassesInfo[dwIndex] ); _ASSERTE( hr == S_OK ); // // Set the fields // hr = pSuperclassInfo->put_Name( bstrName); if(FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "put_Name failed - exit 0x%08x", hr)); // Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } hr = pSuperclassInfo->put_CLSID( bstrCLSID ); if(FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "put_CLSID failed - exit 0x%08x", hr)); // Clean-up delete[] pSuperclassesIID; delete[] ppSuperclassesInfo; pSuperclassReg->Release(); SysFreeString( bstrCLSID ); SysFreeString( bstrName ); return hr; } // // Clean-up // SysFreeString( bstrCLSID ); SysFreeString( bstrName ); } // // Clean-up the IIDs array // pSuperclassReg->Release(); delete[] pSuperclassesIID; // // Create the enumerator object. // typedef CSafeComEnum > CEnumerator; CComObject *pEnum = NULL; hr = CComObject::CreateInstance(&pEnum); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't create enumerator - exit 0x%08x", hr)); delete[] ppSuperclassesInfo; return hr; } // // Query for the desired interface. // hr = pEnum->_InternalQueryInterface( IID_IEnumPluggableSuperclassInfo, (void**) ppSuperclassEnumerator ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't get enumerator interface - exit 0x%08x", hr)); delete pEnum; delete[] ppSuperclassesInfo; return hr; } // // Init the enumerator object. // hr = pEnum->Init(ppSuperclassesInfo, ppSuperclassesInfo + dwNumSuperclasses, NULL, AtlFlagTakeOwnership); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - " "can't init enumerator - exit 0x%08x", hr)); (*ppSuperclassEnumerator)->Release(); delete[] ppSuperclassesInfo; return hr; } LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableSuperclasses - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::get_PluggableTerminalClasses( IN BSTR bstrTerminalSuperclass, IN long lMediaType, OUT VARIANT * pVariant ) { LOG((MSP_TRACE, "CMSPAddress::get_PluggableTerminalClasses - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } if( IsBadStringPtr( bstrTerminalSuperclass, (UINT)-1)) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "bad pointer argument - exit E_INVALIDARG")); return E_INVALIDARG; } IID iidSuperclass = IID_NULL; HRESULT hr = IIDFromString( bstrTerminalSuperclass, &iidSuperclass); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "bad pointer argument - exit E_INVALIDARG")); return E_INVALIDARG; } // // Get ITTemrinalManager2 // ITTerminalManager2* pTermMgr2 = NULL; hr = m_pITTerminalManager->QueryInterface( IID_ITTerminalManager2, (void**)&pTermMgr2); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "QI for ITTerminalManager2 failed - returning 0x%08x", hr)); return hr; } // // Create the collection object - see mspcoll.h // typedef CTapiIfCollection< ITPluggableTerminalClassInfo* > ClassCollection; CComObject * pCollection; hr = CComObject::CreateInstance( &pCollection ); if ( FAILED(hr) ) { //Clean-up pTermMgr2->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "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) ) { // Clean-up pTermMgr2->Release(); delete pCollection; LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "QI for IDispatch on collection failed - exit 0x%08x", hr)); return hr; } // // Find out how many superclasses are available. // DWORD dwNumClasses = 0; hr = pTermMgr2->GetPluggableTerminalClasses( iidSuperclass, lMediaType, &dwNumClasses, NULL); if ( FAILED(hr) ) { //Clean-up pTermMgr2->Release(); pDispatch->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "can't get number of terminals - exit 0x%08x", hr)); return hr; } // // Allocate an array of IID. // IID* pClassesIID = new IID[dwNumClasses]; if ( pClassesIID == NULL ) { //Clean-up pTermMgr2->Release(); pDispatch->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "can't allocate IIDs array - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = pTermMgr2->GetPluggableTerminalClasses( iidSuperclass, lMediaType, &dwNumClasses, pClassesIID ); // // Clean-up // pTermMgr2->Release(); if ( FAILED(hr) ) { //Clean-up pDispatch->Release(); delete[] pClassesIID; LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "can't get IIDs - exit 0x%08x", hr)); return hr; } // // Allocate an array of ITPluggableTerminalClassInfo // typedef ITPluggableTerminalClassInfo* ClassPtr; ClassPtr * ppClassesInfo = new ClassPtr[dwNumClasses]; if ( ppClassesInfo == NULL ) { //Clean-up pDispatch->Release(); delete[] pClassesIID; LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "can't allocate ClassPtr array - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Get ITPluggableTerminalClassRegistration interface // ITPluggableTerminalClassRegistration* pClassReg = NULL; hr = CoCreateInstance( CLSID_PluggableTerminalRegistration, NULL, CLSCTX_INPROC_SERVER, IID_ITPluggableTerminalClassRegistration, (void**)&pClassReg ); if( FAILED(hr) ) { //Clean-up pDispatch->Release(); delete[] pClassesIID; delete[] ppClassesInfo; LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "QI for ITPluggableTerminalClassRegistration - exit 0x%08x",hr)); return hr; } // // Create the objects // for(DWORD dwIndex = 0; dwIndex < dwNumClasses; dwIndex++) { // // Get the string from the IID // LPOLESTR lpszPublicCLSID = NULL; hr = StringFromIID( pClassesIID[dwIndex], &lpszPublicCLSID); if( FAILED(hr) ) { //Clean-up pDispatch->Release(); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "StringFromIID failed - exit 0x%08x",hr)); return hr; } // // Get BSTR for IID // BSTR bstrPublicCLSID = SysAllocString( lpszPublicCLSID ); CoTaskMemFree( lpszPublicCLSID ); // Clean-up if( NULL == bstrPublicCLSID) { //Clean-up pDispatch->Release(); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "SysAllocString failed - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Read information from registry // pClassReg->put_TerminalClass( bstrPublicCLSID); hr = pClassReg->GetTerminalClassInfo( bstrTerminalSuperclass); if( FAILED(hr) ) { // Clean-up pDispatch->Release(); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); SysFreeString( bstrPublicCLSID); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "GetTerminalInfo failed - exit 0x%08x",hr)); return hr; } // // Get the name // BSTR bstrName = NULL; pClassReg->get_Name( &bstrName ); BSTR bstrCompany = NULL; pClassReg->get_Company( &bstrCompany ); BSTR bstrVersion = NULL; pClassReg->get_Version( &bstrVersion ); BSTR bstrCLSID = NULL; pClassReg->get_CLSID( &bstrCLSID ); TMGR_DIRECTION Direction = TMGR_TD_CAPTURE; pClassReg->get_Direction( &Direction ); long lMediaType = 0; pClassReg->get_MediaTypes( &lMediaType ); // // Create the information object // CComObject* pClassInfo = NULL; hr = CComObject::CreateInstance(&pClassInfo); if( FAILED(hr) ) { //Clean-up pDispatch->Release(); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); SysFreeString( bstrPublicCLSID ); SysFreeString( bstrName ); SysFreeString( bstrCompany ); SysFreeString( bstrVersion ); SysFreeString( bstrCLSID ); LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - " "CreateInstance failed - exit 0x%08x", hr)); return hr; } // // Get ITPluggableTerminalClassInfo from this superclass // pClassInfo->QueryInterface( IID_ITPluggableTerminalClassInfo, (void**)&ppClassesInfo[dwIndex] ); // // Set the fields // if( NULL == bstrName) { bstrName = SysAllocString(L""); } pClassInfo->put_Name( bstrName); pClassInfo->put_TerminalClass( bstrPublicCLSID ); if( NULL == bstrCompany) { bstrCompany = SysAllocString(L""); } pClassInfo->put_Company( bstrCompany ); if( NULL == bstrVersion) { bstrVersion = SysAllocString(L""); } pClassInfo->put_Version( bstrVersion ); if( NULL == bstrCLSID) { LPOLESTR lpszCLSID = NULL; StringFromCLSID( CLSID_NULL, &lpszCLSID); bstrCLSID = SysAllocString(lpszCLSID); CoTaskMemFree( lpszCLSID); } pClassInfo->put_CLSID( bstrCLSID ); TERMINAL_DIRECTION TermDirection = TD_CAPTURE; switch( Direction ) { case TMGR_TD_RENDER: TermDirection = TD_RENDER; break; case TMGR_TD_BOTH: TermDirection = TD_BIDIRECTIONAL; break; case TMGR_TD_CAPTURE: default: TermDirection = TD_CAPTURE; break; } hr = pClassInfo->put_Direction( TermDirection ); _ASSERTE(hr == S_OK ); hr = pClassInfo->put_MediaTypes( lMediaType ); _ASSERTE(hr == S_OK ); // // Clean-up // SysFreeString( bstrPublicCLSID ); SysFreeString( bstrName ); SysFreeString( bstrCompany ); SysFreeString( bstrVersion ); SysFreeString( bstrCLSID ); } // // Clean-up the IIDs array // pClassReg->Release(); delete[] pClassesIID; // // Init the collection using an iterator -- pointers to the beginning and // the ending element plus one. If it succeeds, this method addrefs each // element of ppterminals by querying for IDispatch. // hr = pCollection->Initialize( dwNumClasses, ppClassesInfo, ppClassesInfo + dwNumClasses ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - exit " "pCollection->Initialize failed. returns 0x%08x", hr)); delete[] ppClassesInfo; pDispatch->Release(); return hr; } // // put the IDispatch interface pointer into the variant // LOG((MSP_INFO, "CMSPAddress::get_PluggableTerminalClasses - " "placing IDispatch value %08x in variant", pDispatch)); VariantInit(pVariant); pVariant->vt = VT_DISPATCH; pVariant->pdispVal = pDispatch; LOG((MSP_TRACE, "CMSPAddress::get_PluggableTerminalClasses - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::EnumeratePluggableTerminalClasses( IN CLSID iidTerminalSuperclass, IN long lMediaType, OUT IEnumPluggableTerminalClassInfo ** ppClassEnumerator ) { LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableTerminalClasses - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(ppClassEnumerator, sizeof(IEnumPluggableTerminalClassInfo *) ) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } LPOLESTR lpszCLSID = NULL; HRESULT hr = StringFromCLSID( iidTerminalSuperclass, &lpszCLSID); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "StringFromCLSID failed - exit 0x%08x", hr)); return hr; } BSTR bstrTerminalSuperclass = SysAllocString( lpszCLSID ); // Clean-up CoTaskMemFree(lpszCLSID); lpszCLSID = NULL; if( NULL == bstrTerminalSuperclass ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "SysAllocString failed - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Get ITTemrinalManager2 // ITTerminalManager2* pTermMgr2 = NULL; hr = m_pITTerminalManager->QueryInterface( IID_ITTerminalManager2, (void**)&pTermMgr2); if( FAILED(hr) ) { //Clean-up SysFreeString( bstrTerminalSuperclass ); LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "QI for ITTerminalManager2 failed - returning 0x%08x", hr)); return hr; } // // Find out how many superclasses are available. // DWORD dwNumClasses = 0; hr = pTermMgr2->GetPluggableTerminalClasses( iidTerminalSuperclass, lMediaType, &dwNumClasses, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't get number of terminals - exit 0x%08x", hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); pTermMgr2->Release(); return hr; } // // Allocate an array of IID. // IID* pClassesIID = new IID[dwNumClasses]; if ( pClassesIID == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't allocate IIDs array - exit E_OUTOFMEMORY")); // Clean-up SysFreeString( bstrTerminalSuperclass ); pTermMgr2->Release(); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = pTermMgr2->GetPluggableTerminalClasses( iidTerminalSuperclass, lMediaType, &dwNumClasses, pClassesIID ); // // Clean-up // pTermMgr2->Release(); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't get IIDs - exit 0x%08x", hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; return hr; } // // Allocate an array of ITPluggableTerminalClassInfo // typedef ITPluggableTerminalClassInfo* ClassPtr; ClassPtr * ppClassesInfo = new ClassPtr[dwNumClasses]; if ( ppClassesInfo == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't allocate ClassPtr array - exit E_OUTOFMEMORY")); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; return E_OUTOFMEMORY; } // // Get ITPluggableTerminalClassRegistration interface // ITPluggableTerminalClassRegistration* pClassReg = NULL; hr = CoCreateInstance( CLSID_PluggableTerminalRegistration, NULL, CLSCTX_INPROC_SERVER, IID_ITPluggableTerminalClassRegistration, (void**)&pClassReg ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "QI for ITPluggableTerminalClassRegistration - exit 0x%08x",hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] ppClassesInfo; delete[] pClassesIID; return hr; } // // Create the objects // for(DWORD dwIndex = 0; dwIndex < dwNumClasses; dwIndex++) { // // Get the string from the IID // LPOLESTR lpszPublicCLSID = NULL; hr = StringFromIID( pClassesIID[dwIndex], &lpszPublicCLSID); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "StringFromIID failed - exit 0x%08x",hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); return hr; } // // Get BSTR for IID // BSTR bstrPublicCLSID = SysAllocString( lpszPublicCLSID ); CoTaskMemFree( lpszPublicCLSID ); // Clean-up if( NULL == bstrPublicCLSID) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "SysAllocString failed - exit E_OUTOFMEMORY")); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); return E_OUTOFMEMORY; } // // Read information from registry // pClassReg->put_TerminalClass( bstrPublicCLSID); hr = pClassReg->GetTerminalClassInfo( bstrTerminalSuperclass); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "GetTerminalInfo failed - exit 0x%08x",hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); SysFreeString( bstrPublicCLSID); return hr; } // // Get the name // BSTR bstrName = NULL; pClassReg->get_Name( &bstrName ); BSTR bstrCompany = NULL; pClassReg->get_Company( &bstrCompany ); BSTR bstrVersion = NULL; pClassReg->get_Version( &bstrVersion ); BSTR bstrCLSID = NULL; pClassReg->get_CLSID( &bstrCLSID ); TMGR_DIRECTION Direction = TMGR_TD_CAPTURE; pClassReg->get_Direction( &Direction ); long lMediaType = 0; pClassReg->get_MediaTypes( &lMediaType ); // // Create the information object // CComObject* pClassInfo = NULL; hr = CComObject::CreateInstance(&pClassInfo); if( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "CreateInstance failed - exit 0x%08x", hr)); // Clean-up SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; delete[] ppClassesInfo; pClassReg->Release(); SysFreeString( bstrPublicCLSID ); SysFreeString( bstrName ); SysFreeString( bstrCompany ); SysFreeString( bstrVersion ); SysFreeString( bstrCLSID ); return hr; } // // Get ITPluggableTerminalClassInfo from this superclass // hr = pClassInfo->QueryInterface( IID_ITPluggableTerminalClassInfo, (void**)&ppClassesInfo[dwIndex] ); _ASSERTE(hr == S_OK); // // Set the fields // if( NULL == bstrName) { bstrName = SysAllocString(L""); } pClassInfo->put_Name( bstrName); pClassInfo->put_TerminalClass( bstrPublicCLSID ); if( NULL == bstrCompany) { bstrCompany = SysAllocString(L""); } pClassInfo->put_Company( bstrCompany ); if( NULL == bstrVersion) { bstrVersion = SysAllocString(L""); } pClassInfo->put_Version( bstrVersion ); if( NULL == bstrCLSID) { LPOLESTR lpszCLSID = NULL; StringFromCLSID( CLSID_NULL, &lpszCLSID); bstrCLSID = SysAllocString(lpszCLSID); CoTaskMemFree( lpszCLSID); } pClassInfo->put_CLSID( bstrCLSID ); TERMINAL_DIRECTION TermDirection = TD_CAPTURE; switch( Direction ) { case TMGR_TD_RENDER: TermDirection = TD_RENDER; break; case TMGR_TD_BOTH: TermDirection = TD_BIDIRECTIONAL; break; case TMGR_TD_CAPTURE: default: TermDirection = TD_CAPTURE; break; } pClassInfo->put_Direction( TermDirection ); pClassInfo->put_MediaTypes( lMediaType ); // // Clean-up // SysFreeString( bstrPublicCLSID ); SysFreeString( bstrName ); SysFreeString( bstrCompany ); SysFreeString( bstrVersion ); SysFreeString( bstrCLSID ); } // // Clean-up the IIDs array // SysFreeString( bstrTerminalSuperclass ); delete[] pClassesIID; pClassReg->Release(); // // Create the enumerator object. // typedef CSafeComEnum > CEnumerator; CComObject *pEnum = NULL; hr = CComObject::CreateInstance(&pEnum); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't create enumerator - exit 0x%08x", hr)); delete[] ppClassesInfo; return hr; } // // Query for the desired interface. // hr = pEnum->_InternalQueryInterface( IID_IEnumPluggableTerminalClassInfo, (void**) ppClassEnumerator ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't get enumerator interface - exit 0x%08x", hr)); delete pEnum; delete[] ppClassesInfo; return hr; } // // Init the enumerator object. // hr = pEnum->Init(ppClassesInfo, ppClassesInfo + dwNumClasses, NULL, AtlFlagTakeOwnership); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - " "can't init enumerator - exit 0x%08x", hr)); (*ppClassEnumerator)->Release(); delete[] ppClassesInfo; return hr; } LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableTerminalClasses - exit S_OK")); return S_OK; } STDMETHODIMP CMSPAddress::GetEvent( IN OUT DWORD * pdwSize, OUT BYTE * pBuffer ) /*++ Routine Description: This method is called by TAPI3 to get detailed information about the event that just happened. TAPI3 will normally do this after its event is signaled. Locks the event list. Arguments: pMSPEvent The MSP_EVENT pdwSize Pointer to a DWORD. On entry, indicates the size in bytes of the buffer pointed to in pbuffer. On success, it will be filled in with the actual number of bytes returned. If the buffer is not big enough, the method will return TAPI_E_NOTENOUGHMEMORY, and it will be filled in the with number of bytes needed. pBuffer Event buffer filled in by MSP with the relevant events Return Value: S_OK E_OUTOFMEMORY TAPI_E_NOEVENT TAPI_E_NOTENOUGHMEMORY --*/ { // We trust TAPI3 not to give us bad pointers. _ASSERTE(!MSPB_IsBadWritePtr(pdwSize, sizeof (DWORD *))); _ASSERTE((*pdwSize == 0) ? TRUE : !MSPB_IsBadWritePtr(pBuffer, sizeof(BYTE) * (*pdwSize))); LOG((MSP_TRACE, "CMSPAddress::GetEvent")); CLock lock(m_EventDataLock); if (IsListEmpty(&m_EventList)) { return TAPI_E_NOEVENT; } // retrieve first entry PLIST_ENTRY pLE = m_EventList.Flink; // convert list entry to structure pointer PMSPEVENTITEM pItem = CONTAINING_RECORD(pLE, MSPEVENTITEM, Link); if (pItem->MSPEventInfo.dwSize > *pdwSize) { *pdwSize = pItem->MSPEventInfo.dwSize; return TAPI_E_NOTENOUGHMEMORY; } CopyMemory(pBuffer, &pItem->MSPEventInfo, pItem->MSPEventInfo.dwSize); *pdwSize = pItem->MSPEventInfo.dwSize; // remove the first entry from the event list. RemoveHeadList(&m_EventList); // free the memory. FreeEventItem(pItem); return S_OK; } HRESULT CMSPAddress::PostEvent( IN MSPEVENTITEM * pEventItem ) /*++ Routine Description: This method is called by MSPCalls to post an event to TAPI3. This method puts the event at the end of the event list and singals TAPI3. Locks the event list. Arguments: EventItem The event to be queued. Return Value: S_OK E_OUTOFMEMORY --*/ { CLock lock(m_EventDataLock); if (m_htEvent == NULL) { return E_UNEXPECTED; // the address was shut down. } InsertTailList(&m_EventList, &pEventItem->Link); SetEvent(m_htEvent); return S_OK; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // OLE Automation wrappers STDMETHODIMP CMSPAddress::get_StaticTerminals ( OUT VARIANT * pVariant ) { LOG((MSP_TRACE, "CMSPAddress::get_StaticTerminals - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) ) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } // // create the collection object - see mspcoll.h // typedef CTapiIfCollection< ITTerminal * > TerminalCollection; CComObject * pCollection; HRESULT hr = CComObject::CreateInstance( &pCollection ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "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, "CMSPAddress::get_StaticTerminals - " "QI for IDispatch on collection failed - exit 0x%08x", hr)); delete pCollection; return hr; } // // Find out how many terminals are available. // DWORD dwNumTerminals; hr = GetStaticTerminals(&dwNumTerminals, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "can't get number of terminals - exit 0x%08x", hr)); pDispatch->Release(); return hr; } // // Allocate an array of terminal pointers. // typedef ITTerminal * TermPtr; TermPtr * ppTerminals = new TermPtr[dwNumTerminals]; if ( ppTerminals == NULL ) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "can't allocate terminals array - exit E_OUTOFMEMORY")); pDispatch->Release(); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = GetStaticTerminals(&dwNumTerminals, ppTerminals); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "can't get terminals - exit 0x%08x", hr)); pDispatch->Release(); delete ppTerminals; return hr; } // // Init the collection using an iterator -- pointers to the beginning and // the ending element plus one. If it succeeds, this method addrefs each // element of ppterminals by querying for IDispatch. // hr = pCollection->Initialize( dwNumTerminals, ppTerminals, ppTerminals + dwNumTerminals ); // // Release the ITTerminal reference to each terminal (leaving the // IDispatch reference, if any). Then delete the array; the // collection is now storing the pointers. // for (DWORD i = 0; i < dwNumTerminals; i++) { ppTerminals[i]->Release(); } delete ppTerminals; if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "Initialize on collection failed - exit 0x%08x", hr)); pDispatch->Release(); return hr; } // // put the IDispatch interface pointer into the variant // LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - " "placing IDispatch value %08x in variant", pDispatch)); VariantInit(pVariant); pVariant->vt = VT_DISPATCH; pVariant->pdispVal = pDispatch; LOG((MSP_TRACE, "CMSPAddress::get_StaticTerminals - exit S_OK")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CMSPAddress::EnumerateStaticTerminals ( OUT IEnumTerminal ** ppTerminalEnumerator ) { LOG((MSP_TRACE, "CMSPAddress::EnumerateStaticTerminals - " "enter")); // // Check the return pointer. // if ( MSPB_IsBadWritePtr(ppTerminalEnumerator, sizeof(IEnumTerminal *) ) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "bad return pointer - exit E_POINTER")); return E_POINTER; } // // Create the enumerator object. // typedef _CopyInterface CCopy; typedef CSafeComEnum CEnumerator; HRESULT hr; CComObject *pEnum = NULL; hr = CComObject::CreateInstance(&pEnum); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "can't create enumerator - exit 0x%08x", hr)); return hr; } // // Query for the desired interface. // hr = pEnum->_InternalQueryInterface(IID_IEnumTerminal, (void**) ppTerminalEnumerator); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "can't get enumerator interface - exit 0x%08x", hr)); delete pEnum; return hr; } // // Find out how many terminals are available. // DWORD dwNumTerminals; hr = GetStaticTerminals(&dwNumTerminals, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "can't get number of terminals - exit 0x%08x", hr)); (*ppTerminalEnumerator)->Release(); return hr; } // // Allocate an array of terminal pointers. // typedef ITTerminal * TermPtr; TermPtr * ppTerminals = new TermPtr[dwNumTerminals]; if ( ppTerminals == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "can't allocate terminals array - exit E_OUTOFMEMORY")); (*ppTerminalEnumerator)->Release(); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. We must do this before // initializing the enumerator, because the enumerator may want to // addref the interface pointers during initialize. // hr = GetStaticTerminals(&dwNumTerminals, ppTerminals); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - " "can't get terminals - exit 0x%08x", hr)); (*ppTerminalEnumerator)->Release(); delete ppTerminals; return hr; } // // Initialize the object with the array of pointers. // hr = pEnum->Init(ppTerminals, ppTerminals + dwNumTerminals, NULL, AtlFlagTakeOwnership); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPCallBase::EnumerateStaticTerminals - " "init enumerator failed - exit 0x%08x", hr)); for (DWORD i = 0; i < dwNumTerminals; i++) { ppTerminals[i]->Release(); } delete ppTerminals; (*ppTerminalEnumerator)->Release(); return hr; } LOG((MSP_TRACE, "CMSPAddress::EnumerateStaticTerminals - exit S_OK")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CMSPAddress::get_DynamicTerminalClasses ( OUT VARIANT * pVariant ) { LOG((MSP_TRACE, "CMSPAddress::get_DynamicTerminalClasses - enter")); // // Check parameters. // if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) ) { LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - " "bad pointer argument - exit E_POINTER")); return E_POINTER; } // // create the collection object - see mspcoll.h // CComObject * pCollection; HRESULT hr = CComObject::CreateInstance( &pCollection ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - " "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, "CMSPAddress::get_DynamicTerminalClasses - " "QI for IDispatch on collection failed - exit 0x%08x", hr)); delete pCollection; return hr; } // // Find out how many terminals classes are available. // DWORD dwNumClasses; hr = GetDynamicTerminalClasses(&dwNumClasses, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't get number of terminal classes - exit 0x%08x", hr)); pDispatch->Release(); return hr; } // // Allocate an array of GUIDs. // IID * pClassGuids = new IID[dwNumClasses]; if ( pClassGuids == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't allocate class guids array - exit E_OUTOFMEMORY")); pDispatch->Release(); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. // hr = GetDynamicTerminalClasses(&dwNumClasses, pClassGuids); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't get terminal class guids - exit 0x%08x", hr)); pDispatch->Release(); delete [] pClassGuids; return hr; } // // Allocate an array of BSTRs. // BSTR * pClassBstrs = new BSTR[dwNumClasses]; if ( pClassBstrs == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't allocate class bstrs array - exit E_OUTOFMEMORY")); pDispatch->Release(); delete [] pClassGuids; return E_OUTOFMEMORY; } // // Allocate a string for each GUID and copy it to the array, // then delete the array of GUIDs. // const int BUFSIZE = 100; WCHAR wszBuffer[BUFSIZE]; for (DWORD i = 0; i < dwNumClasses; i++) { int ret = StringFromGUID2(pClassGuids[i], wszBuffer, BUFSIZE); _ASSERTE(ret != 0); pClassBstrs[i] = SysAllocString(wszBuffer); if ( pClassBstrs[i] == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't allocate a bstr - exit E_OUTOFMEMORY")); for (DWORD j = 0; j < i; j++) { SysFreeString(pClassBstrs[j]); } delete [] pClassBstrs; delete [] pClassGuids; pDispatch->Release(); return E_OUTOFMEMORY; } } delete [] pClassGuids; // // Init the collection using an iterator -- pointers to the beginning and // the ending element plus one. // hr = pCollection->Initialize( dwNumClasses, pClassBstrs, pClassBstrs + dwNumClasses ); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - " "Initialize on collection failed - exit 0x%08x", hr)); pDispatch->Release(); for (DWORD k = 0; k < dwNumClasses; k++) { SysFreeString(pClassBstrs[k]); } delete [] pClassBstrs; return hr; } delete [] pClassBstrs; // // put the IDispatch interface pointer into the variant // LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - " "placing IDispatch value %08x in variant", pDispatch)); VariantInit(pVariant); pVariant->vt = VT_DISPATCH; pVariant->pdispVal = pDispatch; LOG((MSP_TRACE, "CMSPAddress::get_DynamicTerminalClasses - exit S_OK")); return S_OK; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CMSPAddress::EnumerateDynamicTerminalClasses ( OUT IEnumTerminalClass ** ppTerminalClassEnumerator ) { LOG((MSP_TRACE, "CMSPAddress::EnumerateDynamicTerminalClasses - enter")); // // Check the return pointer. // if ( MSPB_IsBadWritePtr(ppTerminalClassEnumerator, sizeof(IEnumTerminalClass *) ) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "bad return pointer - exit E_POINTER")); return E_POINTER; } // // Find out how many terminals classes are available. // HRESULT hr; DWORD dwNumClasses; hr = GetDynamicTerminalClasses(&dwNumClasses, NULL); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't get number of terminal classes - exit 0x%08x", hr)); return hr; } // // Allocate an array of GUIDs. // IID * pClassGuids = new IID[dwNumClasses]; if ( pClassGuids == NULL ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't allocate class guids array - exit E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Fill in the array with actual pointers. // hr = GetDynamicTerminalClasses(&dwNumClasses, pClassGuids); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't get terminal class guids - exit 0x%08x", hr)); delete [] pClassGuids; return hr; } // // Create an enumerator to hold this array, and have it take ownership // so that it will delete the array when it is released. The CSafeComEnum // can handle zero-length arrays. This Fn also checks the return arg. // // // Create the enumerator object. // typedef CSafeComEnum > CEnumerator; CComObject *pEnum = NULL; hr = CComObject::CreateInstance(&pEnum); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't create enumerator - exit 0x%08x", hr)); delete [] pClassGuids; return hr; } // // Query for the desired interface. // hr = pEnum->_InternalQueryInterface(IID_IEnumTerminalClass, (void**) ppTerminalClassEnumerator); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't get enumerator interface - exit 0x%08x", hr)); delete pEnum; delete [] pClassGuids; return hr; } // // Init the enumerator object. // hr = pEnum->Init(pClassGuids, pClassGuids + dwNumClasses, NULL, AtlFlagTakeOwnership); if ( FAILED(hr) ) { LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - " "can't init enumerator - exit 0x%08x", hr)); (*ppTerminalClassEnumerator)->Release(); delete [] pClassGuids; return hr; } LOG((MSP_TRACE, "CMSPAddress::EnumerateDynamicTerminalClasses - exit S_OK")); return S_OK; } HRESULT CMSPAddress::ReceiveTSPAddressData( IN PBYTE pBuffer, IN DWORD dwSize ) /*++ Routine Description: Base class receive TSP address data method... does nothing in base class. Implemented so that MSP's that only communicate per-call don't have to override it. Arguments: Return Value: S_OK --*/ { LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPAddressData - enter")); LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPAddressData - exit S_OK")); return S_OK; } HRESULT CMSPAddress::PnpNotifHandler( IN BOOL bDeviceArrival ) { LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - enter")); if (bDeviceArrival) LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - device arrival")); else LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - device removal")); // lock the terminal related data. This is a auto lock that will unlock // when the function returns. CLock lock(m_TerminalDataLock); // if the terminal list hasn't been built yet, we can skip doing anything if (m_fTerminalsUpToDate) { HRESULT hr = UpdateTerminalListForPnp( bDeviceArrival ); if (FAILED(hr)) { LOG((MSP_ERROR, "CMSPAddress::PnpNotifHandler - " "UpdateTerminalList failed - returning 0x%08x", hr)); return hr; } } LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - exit S_OK")); return S_OK; } // eof