windows-nt/Source/XPSP1/NT/net/tapi/skywalker/mspbase/mspterm.cpp

758 lines
21 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
mspterm.cpp
Abstract:
Implementations for the CBaseTerminal, CSingleFilterTerminal, and various
work item / worker thread classes.
--*/
#include "precomp.h"
#pragma hdrstop
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CBaseTerminal::CBaseTerminal()
: m_TerminalDirection(TD_CAPTURE)
, m_TerminalType(TT_STATIC)
, m_TerminalState(TS_NOTINUSE)
, m_TerminalClassID(CLSID_NULL)
, m_pFTM(NULL)
{
LOG((MSP_TRACE, "CBaseTerminal::CBaseTerminal() called"));
HRESULT hr = CoCreateFreeThreadedMarshaler(
GetControllingUnknown(), &m_pFTM);
if ( FAILED(hr) )
{
LOG((MSP_TRACE, "CBaseTerminal::CBaseTerminal() - create ftm failed"));
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CBaseTerminal::~CBaseTerminal()
{
if (NULL != m_pFTM)
{
m_pFTM->Release();
}
LOG((MSP_TRACE, "CBaseTerminal::~CBaseTerminal() finished"));
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Dynamic terminals that support only one direction must override this to check
// if the direction is valid (although the terminal manager is supposed to
// ensure that the wrong direction is never passed). Dynamic terminal might want
// to override this for other reasons too (create filters now, etc.).
//
// Static terminals normally just call this in their CreateTerminal().
//
HRESULT CBaseTerminal::Initialize(
IN IID iidTerminalClass,
IN DWORD dwMediaType,
IN TERMINAL_DIRECTION Direction,
IN MSP_HANDLE htAddress
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::Initialize - enter"));
//
// Check if the media type is supported by this terminal.
//
if ( ! MediaTypeSupported( (long) dwMediaType) )
{
LOG((MSP_ERROR, "CBaseTerminal::Initialize - "
"media type not supported - returning E_INVALIDARG"));
return E_INVALIDARG;
}
//
// Save this configurarion.
//
m_dwMediaType = dwMediaType;
m_TerminalDirection = Direction;
m_TerminalClassID = iidTerminalClass;
m_htAddress = htAddress;
LOG((MSP_TRACE, "CBaseTerminal::Initialize - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_AddressHandle (
OUT MSP_HANDLE * phtAddress
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_AddressHandle - enter"));
if ( MSPB_IsBadWritePtr( phtAddress, sizeof(MSP_HANDLE) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_AddressHandle - returning E_POINTER"));
return E_POINTER;
}
*phtAddress = m_htAddress;
LOG((MSP_TRACE, "CBaseTerminal::get_AddressHandle - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_Name(BSTR * pbsName)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_Name - enter"));
if ( MSPB_IsBadWritePtr( pbsName, sizeof(BSTR) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_Name - "
"bad BSTR passed in - returning E_POINTER"));
return E_POINTER;
}
*pbsName = SysAllocString(m_szName);
if ( *pbsName == NULL )
{
LOG((MSP_ERROR, "CBaseTerminal::get_Name - "
"can't sysallocstring - returning E_OUTOFMEMORY"));
return E_OUTOFMEMORY;
}
LOG((MSP_TRACE, "CBaseTerminal::get_Name - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_State(TERMINAL_STATE * pVal)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_State - enter"));
if ( MSPB_IsBadWritePtr( pVal, sizeof(TERMINAL_STATE) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_State - returning E_POINTER"));
return E_POINTER;
}
*pVal = m_TerminalState;
LOG((MSP_TRACE, "CBaseTerminal::get_State - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_TerminalType(TERMINAL_TYPE * pVal)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_TerminalType - enter"));
if ( MSPB_IsBadWritePtr( pVal, sizeof(TERMINAL_TYPE) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_TerminalType - returning E_POINTER"));
return E_POINTER;
}
*pVal = m_TerminalType;
LOG((MSP_TRACE, "CBaseTerminal::get_TerminalType - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_TerminalClass(BSTR * pbsClassID)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_TerminalClass - enter"));
if ( MSPB_IsBadWritePtr( pbsClassID, sizeof(BSTR) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_TerminalClass - returning E_POINTER"));
return E_POINTER;
}
//
// Convert the CLSID to an OLE string.
//
LPOLESTR lposClass = NULL;
HRESULT hr = StringFromCLSID(m_TerminalClassID, &lposClass);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CBaseTerminal::get_TerminalClass (StringFromCLSID) - returning %8x", hr));
return hr;
}
//
// Put the string in a BSTR.
//
*pbsClassID = ::SysAllocString(lposClass);
//
// Free the OLE string.
//
::CoTaskMemFree(lposClass);
if (*pbsClassID == NULL)
{
LOG((MSP_ERROR, "CBaseTerminal::get_TerminalClass - returning E_OUTOFMEMORY"));
return E_OUTOFMEMORY;
}
LOG((MSP_TRACE, "CBaseTerminal::get_TerminalClass - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_Direction(
OUT TERMINAL_DIRECTION *pDirection
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_Direction - enter"));
if ( MSPB_IsBadWritePtr( pDirection, sizeof(TERMINAL_DIRECTION) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_Direction - returning E_POINTER"));
return E_POINTER;
}
*pDirection = m_TerminalDirection;
LOG((MSP_TRACE, "CBaseTerminal::get_Direction - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// enters each of the internal filters into the filter graph
// connects the internal filters together (if applicable)
// and returns all the filters to be used as connection points
STDMETHODIMP CBaseTerminal::ConnectTerminal(
IN IGraphBuilder * pGraph,
IN DWORD dwTerminalDirection,
IN OUT DWORD * pdwNumPins,
OUT IPin ** ppPins
)
{
LOG((MSP_TRACE, "CBaseTerminal::ConnectTerminal - enter"));
//
// Check parameters.
//
if ( IsBadReadPtr(pGraph, sizeof(IGraphBuilder) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"bad graph pointer; exit E_POINTER"));
return E_POINTER;
}
if ( MSPB_IsBadWritePtr(pdwNumPins, sizeof(DWORD) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"bad numpins pointer; exit E_POINTER"));
return E_POINTER;
}
//
// Find out how many pins we expose. For most terminals this is
// straightforward but we pass in the graph pointer in case they
// need to do something funky to figure this out.
//
DWORD dwActualNumPins;
HRESULT hr;
hr = GetNumExposedPins(pGraph, &dwActualNumPins);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"GetNumExposedPins failed - exit 0x%08x", hr));
return hr;
}
//
// If ppPins is NULL, just return the number of pins and don't try to
// connect the terminal.
//
if ( ppPins == NULL )
{
LOG((MSP_TRACE, "CBaseTerminal::ConnectTerminal - "
"returned number of exposed pins - exit S_OK"));
*pdwNumPins = dwActualNumPins;
return S_OK;
}
//
// Otherwise, we have a pin return buffer. Check that the purported buffer
// size is big enough and that the buffer is actually writable to the size
// we need.
//
if ( *pdwNumPins < dwActualNumPins )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"not enough space to place pins; exit TAPI_E_NOTENOUGHMEMORY"));
*pdwNumPins = dwActualNumPins;
return TAPI_E_NOTENOUGHMEMORY;
}
if ( MSPB_IsBadWritePtr(ppPins, dwActualNumPins * sizeof(IPin *) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"bad pins array pointer; exit E_POINTER"));
return E_POINTER;
}
//
// Check if we're already connected, and if so, change our state to
// connected. Note that this makes sense for both core static terminals
// and dynamic terminals. Also note that we need to protect this with
// a critical section, but after this we can let go of the lock because
// anyone who subsequently enters the critical section will bail at this
// point.
//
{
CLock lock(m_CritSec);
//
// check if already connected
//
if (TS_INUSE == m_TerminalState)
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"terminal already in use; exit TAPI_E_TERMINALINUSE"));
return TAPI_E_TERMINALINUSE;
}
//
// Save important state.
//
m_pGraph = pGraph;
m_TerminalState = TS_INUSE;
}
// add filters to the filter graph
hr = AddFiltersToGraph();
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"can't add filters to graph"));
goto disconnect_terminal;
}
// Give the terminal a chance to do any preconnection
hr = ConnectFilters();
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"can't do internal filter connection"));
goto disconnect_terminal;
}
//
// Get the pins that this filter exposes. No need to pass in
// the filter graph because we already saved the graph pointer.
//
*pdwNumPins = dwActualNumPins;
hr = GetExposedPins(ppPins);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CBaseTerminal::ConnectTerminal - "
"can't get exposed pins"));
goto disconnect_terminal;
}
LOG((MSP_TRACE, "CBaseTerminal::ConnectTerminal success"));
return S_OK;
disconnect_terminal:
//
// best effort attempt to disconnect - ignore error code
//
DisconnectTerminal(pGraph, 0);
//
// Release our reference to the graph and set ourselves to notinuse state.
// DisconnectTerminal does this on success, but we need to make sure this
// cleanup happens even if DisconnectTerminal failed.
//
m_pGraph = NULL; // this releases the CComPtr
m_TerminalState = TS_NOTINUSE;
LOG((MSP_TRACE, "CBaseTerminal::ConnectTerminal - exit 0x%08x", hr));
return hr;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP
CBaseTerminal::CompleteConnectTerminal(void)
{
LOG((MSP_TRACE, "CBaseTerminal::CompleteConnectTerminal - enter"));
LOG((MSP_TRACE, "CBaseTerminal::CompleteConnectTerminal - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// disconnects the internal filters from each other (if applicable)
// and removes them from the filter graph (thus breaking connections to
// the stream).
// Filter graph parameter is used for validation, to make sure the terminal
// is disconnected from the same graph that it was originally connected to.
STDMETHODIMP
CBaseTerminal::DisconnectTerminal(
IN IGraphBuilder * pGraph,
IN DWORD dwReserved
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::DisconnectTerminal called"));
//
// If not in use, then there is nothing to be done.
//
if ( TS_INUSE != m_TerminalState )
{
_ASSERTE(m_pGraph == NULL);
LOG((MSP_TRACE, "CBaseTerminal::DisconnectTerminal success; not in use"));
return S_OK;
}
//
// Check that we are being disconnected from the correct graph.
//
if ( m_pGraph != pGraph )
{
LOG((MSP_TRACE, "CBaseTerminal::DisconnectTerminal - "
"wrong graph; returning E_INVALIDARG"));
return E_INVALIDARG;
}
//
// Extra sanity check.
//
if ( m_pGraph == NULL )
{
LOG((MSP_TRACE, "CBaseTerminal::DisconnectTerminal - "
"no graph; returning E_UNEXPECTED"));
return E_UNEXPECTED;
}
HRESULT hr;
//
// Remove filters from the graph
//
hr = RemoveFiltersFromGraph();
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CBaseTerminal::DisconnectTerminal - "
"remove filters from graph failed; returning 0x%08x", hr));
return hr;
}
//
// Release our reference to the graph and set ourselves to notinuse state.
//
m_pGraph = NULL; // this releases the CComPtr
m_TerminalState = TS_NOTINUSE;
LOG((MSP_TRACE, "CBaseTerminal::DisconnectTerminal success"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
STDMETHODIMP CBaseTerminal::get_MediaType(long * plMediaType)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CBaseTerminal::get_MediaType - enter"));
if ( MSPB_IsBadWritePtr(plMediaType, sizeof(long) ) )
{
LOG((MSP_ERROR, "CBaseTerminal::get_MediaType - returning E_POINTER"));
return E_POINTER;
}
*plMediaType = (long) m_dwMediaType;
LOG((MSP_TRACE, "CBaseTerminal::get_MediaType - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL CBaseTerminal::MediaTypeSupported(long lMediaType)
{
return IsValidSingleMediaType( (DWORD) lMediaType,
GetSupportedMediaTypes() );
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// CSingleFilterTerminal //
// //
// This is a base class for a terminal with a single filter and pin. The //
// terminal could be any direction or media type, and it could be static //
// or dynamic. //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT CSingleFilterTerminal::GetNumExposedPins(
IN IGraphBuilder * pGraph,
OUT DWORD * pdwNumPins)
{
LOG((MSP_TRACE, "CSingleFilterTerminal::GetNumExposedPins - enter"));
//
// We ignote pGraph because we don't need to do anything special to find
// out how many pins we have.
//
*pdwNumPins = 1;
LOG((MSP_TRACE, "CSingleFilterTerminal::GetNumExposedPins - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HRESULT CSingleFilterTerminal::GetExposedPins(
OUT IPin ** ppPins
)
{
LOG((MSP_TRACE, "CSingleFilterTerminal::GetExposedPins - enter"));
_ASSERTE( ! MSPB_IsBadWritePtr(ppPins, 1 * sizeof(IPin *) ) );
//
// Return our single pin.
//
*ppPins = m_pIPin;
(*ppPins)->AddRef();
LOG((MSP_TRACE, "CSingleFilterTerminal::GetExposedPins - exit S_OK"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// stops the rightmost render filter in the terminal
// (needed for dynamic filter graphs)
STDMETHODIMP CSingleFilterTerminal::RunRenderFilter(void)
{
// check that we're really a render filter
// tell our single filter to run
return E_NOTIMPL;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// stops the rightmost render filter in the terminal
// (needed for dynamic filter graphs)
STDMETHODIMP CSingleFilterTerminal::StopRenderFilter(void)
{
// check that we're really a render filter
// tell our single filter to stop
return E_NOTIMPL;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HRESULT
CSingleFilterTerminal::RemoveFiltersFromGraph(void)
{
LOG((MSP_TRACE, "CSingleFilterTerminal::RemoveFiltersFromGraph - enter"));
if (m_pGraph == NULL)
{
LOG((MSP_ERROR, "CSingleFilterTerminal::RemoveFiltersFromGraph - "
"no graph; returning E_UNEXPECTED"));
return E_UNEXPECTED;
}
if (m_pIFilter == NULL)
{
LOG((MSP_ERROR, "CSingleFilterTerminal::RemoveFiltersFromGraph - "
"no filter; returning E_UNEXPECTED"));
return E_UNEXPECTED;
}
//
// Remove the filter from the graph. This also disconnects any connections
// the filter may have.
//
HRESULT hr = m_pGraph->RemoveFilter(m_pIFilter);
LOG((MSP_TRACE, "CSingleFilterTerminal::RemoveFiltersFromGraph - exit 0x%08x", hr));
return hr;
}
HRESULT
CSingleFilterStaticTerminal::CompareMoniker(
IMoniker *pMoniker
)
{
IMoniker *pReducedMoniker;
IMoniker *pReducedNewMoniker;
IBindCtx *pbc;
HRESULT hr;
hr = CreateBindCtx( 0, &pbc );
if (FAILED(hr))
{
LOG((MSP_ERROR, "CSingleFilterStaticTerminal::CompareMoniker - "
"unable to create bind context"));
return hr;
}
hr = m_pMoniker->Reduce(pbc ,MKRREDUCE_ALL, NULL, &pReducedMoniker);
if (FAILED(hr) || !pReducedMoniker)
{
LOG((MSP_ERROR, "CSingleFilterStaticTerminal::CompareMoniker - "
"unable to reduce moniker"));
pbc->Release(); // release the bind context
return hr;
}
hr = pMoniker->Reduce(pbc ,MKRREDUCE_ALL, NULL, &pReducedNewMoniker);
if (FAILED(hr) || !pReducedNewMoniker)
{
LOG((MSP_ERROR, "CSingleFilterStaticTerminal::CompareMoniker - "
"unable to reduce moniker"));
pbc->Release(); // release the bind context
pReducedMoniker->Release(); // release the reduced moniker
return hr;
}
pbc->Release(); // release the bind context
if (pReducedMoniker->IsEqual(pReducedNewMoniker) == S_OK)
{
LOG((MSP_TRACE, "CSingleFilterStaticTerminal::CompareMoniker - "
"exit - return S_OK"));
pReducedMoniker->Release(); // release the reduced monikers
pReducedNewMoniker->Release();
return S_OK;
}
pReducedMoniker->Release(); // release the reduced monikers
pReducedNewMoniker->Release();
LOG((MSP_TRACE, "CSingleFilterStaticTerminal::CompareMoniker - "
"exit - return S_FALSE"));
return S_FALSE;
}
// eof