679 lines
15 KiB
C++
679 lines
15 KiB
C++
// PlgTerm.cpp: implementation of the CPlgTermSample class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "PlgTerm.h"
|
|
#include <initguid.h>
|
|
#include "GUIDs.h"
|
|
#include "PlgTermFilter.h"
|
|
#include "PlgTermSample_i.c"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CPlgTermSample::CPlgTermSample()
|
|
:m_pEventSink(NULL),
|
|
m_bKnownSafeContext(FALSE)
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::CPlgTermSample enter"));
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CPlgTermSample::~CPlgTermSample()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::~CPlgTermSample enter"));
|
|
|
|
//
|
|
// if we have an event sink, release it
|
|
//
|
|
if( NULL != m_pEventSink )
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::~CPlgTermSample release sink"));
|
|
m_pEventSink->Release();
|
|
m_pEventSink = NULL;
|
|
}
|
|
|
|
//
|
|
// Release free thread marshaler
|
|
//
|
|
if( m_pFTM )
|
|
{
|
|
m_pFTM->Release();
|
|
m_pFTM = NULL;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::~CPlgTermSample exit"));
|
|
}
|
|
|
|
|
|
//
|
|
// ITPlgSampleEvent methods
|
|
//
|
|
|
|
HRESULT CPlgTermSample::FireEvent( long lEventCode)
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::FireEvent enter"));
|
|
//
|
|
// we need a sink before we can fire an event
|
|
//
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
|
|
if (NULL == m_pEventSink)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FireEvent no Sink - exit E_FAIL"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// initilize the structure
|
|
//
|
|
|
|
MSP_EVENT_INFO mspEventInfo;
|
|
|
|
mspEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
|
|
mspEventInfo.Event = ME_PRIVATE_EVENT;
|
|
mspEventInfo.hCall = NULL;
|
|
|
|
mspEventInfo.MSP_PRIVATE_EVENT_INFO.lEventCode = lEventCode;
|
|
|
|
|
|
//
|
|
// put the pointer to our IDispatch interface in the structure
|
|
//
|
|
|
|
HRESULT hr = _InternalQueryInterface(IID_IDispatch,
|
|
reinterpret_cast<void**>(&(mspEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent)));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FireEvent failed to get IDispatch interface - exit hr=0x%08", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// pass event to the msp
|
|
//
|
|
|
|
hr = m_pEventSink->FireEvent(&mspEventInfo);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
//
|
|
// release all interfaces that we are holding.
|
|
// fire event failed so no one else will release them for us.
|
|
//
|
|
mspEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent->Release();
|
|
mspEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent=NULL;
|
|
|
|
LOG((MSP_ERROR, "CPlgTermSample::FireEvent on sink failed - exit hr=0x%08", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// event fired
|
|
//
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::FireEvent exit S_OK"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ITPluggableTerminalEventSinkRegistration - Methods implementation
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPlgTermSample::RegisterSink(
|
|
IN ITPluggableTerminalEventSink *pSink
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::RegisterSink enter"));
|
|
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if (!pSink)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::RegisterSink - "
|
|
"ITPluggableTerminalEventSink invalid pointer - exit 0x%08x", E_POINTER));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Release the old event sink
|
|
//
|
|
|
|
if( NULL != m_pEventSink )
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::RegisterSink - releasing sink [%p]",m_pEventSink));
|
|
m_pEventSink->Release();
|
|
m_pEventSink = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the new event sink
|
|
//
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::RegisterSink - keeping new sink [%p]",pSink));
|
|
|
|
m_pEventSink = pSink;
|
|
m_pEventSink->AddRef();
|
|
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::RegisterSink exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPlgTermSample::UnregisterSink()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::UnregisterSink enter"));
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
|
|
//
|
|
// Release the old event sink
|
|
//
|
|
|
|
if( m_pEventSink )
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::RegisterSink - releasing sink [%p]",m_pEventSink));
|
|
m_pEventSink->Release();
|
|
m_pEventSink = NULL;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::UnregisterSink - exit S_OK"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CPlgTermSample::InitializeDynamic(
|
|
IN IID iidTerminalClass,
|
|
IN DWORD dwMediaType,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
IN MSP_HANDLE htAddress
|
|
)
|
|
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::InitializeDynamic enter"));
|
|
|
|
//
|
|
// make sure the direction is correct - we register it with this direction
|
|
//
|
|
|
|
if (TD_RENDER != Direction)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic"
|
|
" - bad direction [%d] requested. returning 0x%08x",
|
|
Direction, E_INVALIDARG));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// make sure the mediatype is correct - TAPIMEDIATYPE_AUDIO - is how we set it in registry
|
|
//
|
|
|
|
|
|
if ( TAPIMEDIATYPE_AUDIO != dwMediaType)
|
|
{
|
|
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic"
|
|
" - bad media type [%d] requested. returning 0x%08x",
|
|
dwMediaType, E_INVALIDARG));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
//
|
|
// Call the base class method
|
|
//
|
|
LOG((MSP_TRACE, "CPlgTermSample::InitializeDynamic - CBaseTerminal::Initialize with"
|
|
"dwMediaType = 0x%08x, Direction = 0x%08x", dwMediaType, Direction));
|
|
|
|
HRESULT hr;
|
|
hr = CBaseTerminal::Initialize(iidTerminalClass,
|
|
dwMediaType,
|
|
Direction,
|
|
htAddress);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic - "
|
|
"base class method failed - 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set the terminal info
|
|
//
|
|
|
|
hr = SetTerminalInfo();
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic - "
|
|
"SetTerminalInfo failed - 0x%08x", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Create the filter
|
|
//
|
|
|
|
hr = CreateFilter();
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic - "
|
|
"CreateFilter failed - 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get and sets the pin
|
|
//
|
|
|
|
hr = FindPin();
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::InitializeDynamic - "
|
|
"FindPin failed - 0x%08x", hr));
|
|
}
|
|
|
|
m_bKnownSafeContext = TRUE;
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::InitializeDynamic exit - 0x%08x", hr));
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
DWORD CPlgTermSample::GetSupportedMediaTypes()
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::GetSupportedMediaTypes enter "));
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
|
|
DWORD dwMediaType = TAPIMEDIATYPE_AUDIO; //we set this in registry
|
|
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::GetSupportedMediaTypes exit - S_OK "));
|
|
|
|
|
|
return dwMediaType;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT CPlgTermSample::AddFiltersToGraph()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::AddFiltersToGraph enter "));
|
|
|
|
USES_CONVERSION;
|
|
|
|
//
|
|
// Validates m_pGraph
|
|
//
|
|
|
|
if ( m_pGraph == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::AddFiltersToGraph - "
|
|
"we have no graph - returning 0x%08x", E_UNEXPECTED));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Validates m_pIFilter
|
|
//
|
|
|
|
if ( m_pIFilter == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::AddFiltersToGraph - "
|
|
"we have no filter - returning 0x%08x", E_UNEXPECTED));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
//
|
|
// AddFilter returns VFW_S_DUPLICATE_NAME if name is duplicate; still succeeds
|
|
//
|
|
|
|
HRESULT hr = m_pGraph->AddFilter(m_pIFilter, T2CW(m_szName));
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::AddFiltersToGraph - "
|
|
"can not add filter "));
|
|
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::AddFiltersToGraph - exit %08x", hr));
|
|
return hr;
|
|
}
|
|
/*++
|
|
SetTerminalInfo
|
|
|
|
Sets the name of the terminal and the terminal type
|
|
Is called by InitializeDynamic
|
|
--*/
|
|
HRESULT CPlgTermSample::SetTerminalInfo()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::SetTerminalInfo - enter"));
|
|
|
|
//
|
|
// set terminals's name for ITTerminal::get_Name
|
|
//
|
|
|
|
size_t nStringMaxSize = sizeof(m_szName)/sizeof(TCHAR);
|
|
|
|
wcsncpy_s(m_szName,nStringMaxSize , SZTERMNAME, min(_tcslen(SZTERMNAME), nStringMaxSize));
|
|
|
|
|
|
//
|
|
// in case string copy did not append with a zero, do it by hand
|
|
//
|
|
|
|
m_szName[min(_tcslen(SZTERMNAME), nStringMaxSize - 1)] = 0;
|
|
|
|
//
|
|
// set other properties
|
|
//
|
|
|
|
m_TerminalType = TT_DYNAMIC;
|
|
|
|
m_TerminalState = TS_NOTINUSE;
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::SetTerminalInfo - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*++
|
|
CreateFilter
|
|
|
|
Create the internal filter
|
|
Is called by InitializeDynamic
|
|
--*/
|
|
HRESULT CPlgTermSample::CreateFilter()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::CreateFilter - enter"));
|
|
|
|
// Create the filter
|
|
CPlgFilter* pFilter = new CPlgFilter();
|
|
|
|
if( NULL == pFilter )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::CreateFilter - "
|
|
"create filter failed - returning 0x%08x", E_OUTOFMEMORY));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// COM Rule
|
|
pFilter->AddRef();
|
|
|
|
//
|
|
// Get the pin
|
|
//
|
|
|
|
HRESULT hr = pFilter->Initialize( );
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::CreateFilter - "
|
|
"Initialize private failed - returning 0x%08x", hr));
|
|
pFilter->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the IBaseFilter interface
|
|
//
|
|
|
|
hr = pFilter->QueryInterface(
|
|
IID_IBaseFilter,
|
|
(void**)&m_pIFilter
|
|
);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::CreateFilter - "
|
|
"QI for IBaseFilter failed"));
|
|
}
|
|
else
|
|
{
|
|
pFilter->InitializePrivate(this);
|
|
}
|
|
|
|
pFilter->Release();
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::CreateFilter - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
FindPin
|
|
|
|
Get the pin from the filter and set the m_pIPin member
|
|
Is called by InitializeDynamic
|
|
--*/
|
|
HRESULT CPlgTermSample::FindPin()
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::FindPin - enter"));
|
|
|
|
//
|
|
// Validates the filter object (smart pointer)
|
|
//
|
|
|
|
if (m_pIFilter == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FindPin - "
|
|
"filter object is NULL - returning 0x%08x", E_UNEXPECTED));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Make sure the IPin object is not initialized
|
|
//
|
|
|
|
if (m_pIPin != NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FindPin - "
|
|
"already got a pin - returning 0x%08x", E_UNEXPECTED));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT hr;
|
|
IEnumPins* pIEnumPins;
|
|
ULONG cFetched;
|
|
|
|
//
|
|
// Get the pins collection
|
|
//
|
|
|
|
if (FAILED(hr = m_pIFilter->EnumPins(&pIEnumPins)))
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FindPin - "
|
|
"cannot enum pins - returning 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the out pin of the Pluggable Filter
|
|
//
|
|
|
|
if (S_OK != (hr = pIEnumPins->Next(1, &m_pIPin, &cFetched)))
|
|
{
|
|
LOG((MSP_ERROR, "CPlgTermSample::FindPin - "
|
|
"cannot get a pin - returning 0x%08x", hr));
|
|
|
|
hr = (hr == S_FALSE) ? E_FAIL : hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::FindPin - exit 0x%08x", hr));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetInterfaceSafetyOptions
|
|
//
|
|
// this is a safeguard to prevent using this terminal in scripting outside
|
|
// terminal manager context.
|
|
//
|
|
// if we detect that InitializeDynamic has not been called, this method will
|
|
// fail thus marking the object as unsafe for scripting
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPlgTermSample::SetInterfaceSafetyOptions(REFIID riid,
|
|
DWORD dwOptionSetMask,
|
|
DWORD dwEnabledOptions)
|
|
{
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
|
|
//
|
|
// check if we are running in safe context
|
|
//
|
|
|
|
if (!m_bKnownSafeContext)
|
|
{
|
|
|
|
//
|
|
// we have not been initialized properly... someone evil is trying to
|
|
// use this terminal. NO!
|
|
//
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// we are known to safe, so simply delegate request to the base class
|
|
//
|
|
|
|
return CMSPObjectSafetyImpl::SetInterfaceSafetyOptions(riid,
|
|
dwOptionSetMask,
|
|
dwEnabledOptions);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetInterfaceSafetyOptions
|
|
//
|
|
// this is a safeguard to prevent using this terminal in scripting outside
|
|
// terminal manager context.
|
|
//
|
|
// if we detect that InitializeDynamic has not been called, this method will
|
|
// fail thus marking the object as unsafe for scripting
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPlgTermSample::GetInterfaceSafetyOptions(REFIID riid,
|
|
DWORD *pdwSupportedOptions,
|
|
DWORD *pdwEnabledOptions)
|
|
{
|
|
|
|
CLock lock(m_CritSec);
|
|
|
|
|
|
//
|
|
// check if we are running in safe context
|
|
//
|
|
|
|
if (!m_bKnownSafeContext)
|
|
{
|
|
|
|
//
|
|
// we have not been initialized properly... someone evil is trying to
|
|
// use this terminal. NO!
|
|
//
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// we are known to safe, so simply delegate request to the base class
|
|
//
|
|
|
|
return CMSPObjectSafetyImpl::GetInterfaceSafetyOptions(riid,
|
|
pdwSupportedOptions,
|
|
pdwEnabledOptions);
|
|
}
|
|
|
|
|
|
|
|
HRESULT CPlgTermSample::FinalConstruct(void)
|
|
{
|
|
LOG((MSP_TRACE, "CPlgTermSample::FinalConstruct - enter"));
|
|
|
|
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
|
|
& m_pFTM );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CFPTerminal::FinalConstruct - "
|
|
"create FTM returned 0x%08x; exit", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlgTermSample::FinalConstruct - exit S_OK"));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
// eof
|