684 lines
16 KiB
C++
684 lines
16 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
MSPaddr.h
|
|
|
|
Abstract:
|
|
|
|
Declaration of the CMSPAddress
|
|
|
|
--*/
|
|
|
|
#ifndef __MSPADDR_H_
|
|
#define __MSPADDR_H_
|
|
|
|
|
|
typedef struct
|
|
{
|
|
LIST_ENTRY Link; // The link node. See ntrtl.h for detail.
|
|
MSP_EVENT_INFO MSPEventInfo; // The event code.
|
|
|
|
} MSPEVENTITEM, *PMSPEVENTITEM;
|
|
|
|
|
|
//
|
|
// these functions should be used to allocate and deallocate MSPEVENTITEM
|
|
// structures. In case of failure, the caller can call GetLastError()
|
|
// to get exact cause of the failure.
|
|
//
|
|
|
|
//
|
|
// nExtraBytes specifies how many extra (in addition to sizeof(MSPEVENTITEM))
|
|
// bytes to allocate.
|
|
//
|
|
|
|
MSPEVENTITEM *AllocateEventItem(SIZE_T nExtraBytes = 0);
|
|
|
|
BOOL FreeEventItem(MSPEVENTITEM *pEventItemToFree);
|
|
|
|
|
|
typedef HRESULT (*PFNCREATETERM) (
|
|
IN CComPtr<IMoniker> pMoniker,
|
|
IN MSP_HANDLE htAddress,
|
|
OUT ITTerminal **pTerm
|
|
);
|
|
|
|
typedef struct
|
|
{
|
|
DWORD dwMediaType;
|
|
const CLSID * clsidClassManager;
|
|
PFNCREATETERM pfnCreateTerm;
|
|
|
|
} STATIC_TERMINAL_TYPE;
|
|
|
|
class ATL_NO_VTABLE CPlugTerminalClassInfo :
|
|
public IDispatchImpl<ITPluggableTerminalClassInfo, &IID_ITPluggableTerminalClassInfo, &LIBID_TAPI3Lib>,
|
|
public CComObjectRootEx<CComMultiThreadModel>,
|
|
public CMSPObjectSafetyImpl
|
|
{
|
|
public:
|
|
DECLARE_GET_CONTROLLING_UNKNOWN()
|
|
virtual HRESULT FinalConstruct(void);
|
|
|
|
|
|
BEGIN_COM_MAP(CPlugTerminalClassInfo)
|
|
COM_INTERFACE_ENTRY(ITPluggableTerminalClassInfo)
|
|
COM_INTERFACE_ENTRY(IDispatch)
|
|
COM_INTERFACE_ENTRY(IObjectSafety)
|
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
|
END_COM_MAP()
|
|
|
|
public:
|
|
CPlugTerminalClassInfo() :
|
|
m_bstrName(NULL),
|
|
m_bstrCompany(NULL),
|
|
m_bstrVersion(NULL),
|
|
m_bstrCLSID(NULL),
|
|
m_bstrTerminalClass(NULL),
|
|
m_lMediaType(1),
|
|
m_Direction(TD_CAPTURE),
|
|
m_pFTM(NULL)
|
|
{
|
|
}
|
|
|
|
~CPlugTerminalClassInfo()
|
|
{
|
|
if( m_bstrName )
|
|
{
|
|
SysFreeString( m_bstrName );
|
|
}
|
|
|
|
if( m_bstrCompany )
|
|
{
|
|
SysFreeString( m_bstrCompany );
|
|
}
|
|
|
|
if( m_bstrVersion )
|
|
{
|
|
SysFreeString( m_bstrVersion );
|
|
}
|
|
|
|
if( m_bstrCLSID )
|
|
{
|
|
SysFreeString( m_bstrCLSID );
|
|
}
|
|
|
|
if( m_bstrTerminalClass )
|
|
{
|
|
SysFreeString( m_bstrTerminalClass );
|
|
}
|
|
|
|
if( m_pFTM )
|
|
{
|
|
m_pFTM->Release();
|
|
}
|
|
}
|
|
|
|
public:
|
|
STDMETHOD(get_Name)(
|
|
/*[out, retval]*/ BSTR* pName
|
|
);
|
|
|
|
STDMETHOD(get_Company)(
|
|
/*[out, retval]*/ BSTR* pCompany
|
|
);
|
|
|
|
STDMETHOD(get_Version)(
|
|
/*[out, retval]*/ BSTR* pVersion
|
|
);
|
|
|
|
STDMETHOD(get_TerminalClass)(
|
|
/*[out, retval]*/ BSTR* pTerminalClass
|
|
);
|
|
|
|
STDMETHOD(get_CLSID)(
|
|
/*[out, retval]*/ BSTR* pCLSID
|
|
);
|
|
|
|
STDMETHOD(get_Direction)(
|
|
/*[out, retval]*/ TERMINAL_DIRECTION* pDirection
|
|
);
|
|
|
|
STDMETHOD(get_MediaTypes)(
|
|
/*[out, retval]*/ long* pMediaTypes
|
|
);
|
|
|
|
private:
|
|
CMSPCritSection m_CritSect; // Critical Section
|
|
|
|
BSTR m_bstrName;
|
|
BSTR m_bstrCompany;
|
|
BSTR m_bstrVersion;
|
|
BSTR m_bstrTerminalClass;
|
|
BSTR m_bstrCLSID;
|
|
long m_lMediaType;
|
|
TERMINAL_DIRECTION m_Direction;
|
|
|
|
IUnknown* m_pFTM; // pointer to the free threaded marshaler
|
|
|
|
private:
|
|
STDMETHOD(put_Name)(
|
|
/*[in]*/ BSTR bstrName
|
|
);
|
|
|
|
STDMETHOD(put_Company)(
|
|
/*[in]*/ BSTR bstrCompany
|
|
);
|
|
|
|
STDMETHOD(put_Version)(
|
|
/*[in]*/ BSTR bstrVersion
|
|
);
|
|
|
|
STDMETHOD(put_TerminalClass)(
|
|
/*[in]*/ BSTR bstrTerminalClass
|
|
);
|
|
|
|
STDMETHOD(put_CLSID)(
|
|
/*[in]*/ BSTR bstrCLSID
|
|
);
|
|
|
|
STDMETHOD(put_Direction)(
|
|
/*[in]*/ TERMINAL_DIRECTION nDirection
|
|
);
|
|
|
|
STDMETHOD(put_MediaTypes)(
|
|
/*[in]*/ long nMediaTypes
|
|
);
|
|
|
|
friend class CMSPAddress;
|
|
};
|
|
|
|
class ATL_NO_VTABLE CPlugTerminalSuperclassInfo :
|
|
public IDispatchImpl<ITPluggableTerminalSuperclassInfo, &IID_ITPluggableTerminalSuperclassInfo, &LIBID_TAPI3Lib>,
|
|
public CComObjectRootEx<CComMultiThreadModel>,
|
|
public CMSPObjectSafetyImpl
|
|
{
|
|
public:
|
|
|
|
DECLARE_GET_CONTROLLING_UNKNOWN()
|
|
virtual HRESULT FinalConstruct(void);
|
|
|
|
BEGIN_COM_MAP(CPlugTerminalSuperclassInfo)
|
|
COM_INTERFACE_ENTRY(ITPluggableTerminalSuperclassInfo)
|
|
COM_INTERFACE_ENTRY(IDispatch)
|
|
COM_INTERFACE_ENTRY(IObjectSafety)
|
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
|
END_COM_MAP()
|
|
|
|
public:
|
|
CPlugTerminalSuperclassInfo() :
|
|
m_bstrCLSID(NULL),
|
|
m_bstrName(NULL),
|
|
m_pFTM(NULL)
|
|
{
|
|
}
|
|
|
|
~CPlugTerminalSuperclassInfo()
|
|
{
|
|
if( m_bstrName )
|
|
{
|
|
SysFreeString( m_bstrName );
|
|
}
|
|
|
|
if( m_bstrCLSID )
|
|
{
|
|
SysFreeString( m_bstrCLSID );
|
|
}
|
|
|
|
if( m_pFTM )
|
|
{
|
|
m_pFTM->Release();
|
|
}
|
|
}
|
|
|
|
public:
|
|
STDMETHOD(get_Name)(
|
|
/*[out, retval]*/ BSTR* pName
|
|
);
|
|
|
|
STDMETHOD(get_CLSID)(
|
|
/*[out, retval]*/ BSTR* pCLSID
|
|
);
|
|
|
|
private:
|
|
CMSPCritSection m_CritSect; // Critical Section
|
|
|
|
BSTR m_bstrCLSID;
|
|
BSTR m_bstrName;
|
|
|
|
IUnknown* m_pFTM; // pointer to the free threaded marshaler
|
|
|
|
private:
|
|
STDMETHOD(put_Name)(
|
|
/*[in]*/ BSTR bstrName
|
|
);
|
|
|
|
STDMETHOD(put_CLSID)(
|
|
/*[in]*/ BSTR bstrCLSID
|
|
);
|
|
|
|
friend class CMSPAddress;
|
|
};
|
|
|
|
/*++
|
|
|
|
Class Description:
|
|
|
|
Represents an MSP address.
|
|
|
|
--*/
|
|
|
|
class ATL_NO_VTABLE CMSPAddress :
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
public ITMSPAddress,
|
|
public IDispatchImpl<ITTerminalSupport2, &IID_ITTerminalSupport2, &LIBID_TAPI3Lib>
|
|
{
|
|
public:
|
|
|
|
// No need for free thread marshaling, because the MSP address object is
|
|
// always aggregated by the TAPI3 address object.
|
|
|
|
BEGIN_COM_MAP( CMSPAddress )
|
|
COM_INTERFACE_ENTRY( ITMSPAddress )
|
|
COM_INTERFACE_ENTRY( IDispatch )
|
|
COM_INTERFACE_ENTRY( ITTerminalSupport )
|
|
COM_INTERFACE_ENTRY( ITTerminalSupport2 )
|
|
END_COM_MAP()
|
|
|
|
// The DERIVED class should DECLARE_AGGREGATABLE(className)
|
|
|
|
DECLARE_GET_CONTROLLING_UNKNOWN()
|
|
|
|
DECLARE_VQI()
|
|
|
|
CMSPAddress();
|
|
virtual ~CMSPAddress();
|
|
virtual ULONG MSPAddressAddRef(void) = 0;
|
|
virtual ULONG MSPAddressRelease(void) = 0;
|
|
|
|
|
|
|
|
// ITMSPAddress methods, called by TAPI.
|
|
STDMETHOD (Initialize) (
|
|
IN MSP_HANDLE htEvent
|
|
);
|
|
|
|
STDMETHOD (Shutdown) ();
|
|
|
|
STDMETHOD (CreateMSPCall) (
|
|
IN MSP_HANDLE htCall,
|
|
IN DWORD dwReserved,
|
|
IN DWORD dwMediaType,
|
|
IN IUnknown * pOuterUnknown,
|
|
OUT IUnknown ** ppMSPCall
|
|
) = 0;
|
|
|
|
STDMETHOD (ShutdownMSPCall) (
|
|
IN IUnknown * pMSPCall
|
|
) = 0;
|
|
|
|
STDMETHOD (ReceiveTSPData) (
|
|
IN IUnknown * pMSPCall,
|
|
IN LPBYTE pBuffer,
|
|
IN DWORD dwBufferSize
|
|
);
|
|
|
|
STDMETHOD (GetEvent) (
|
|
IN OUT DWORD * pdwSize,
|
|
OUT BYTE * pBuffer
|
|
);
|
|
|
|
// ITTerminalSupport methods, called by TAPI and/or the app.
|
|
STDMETHOD (get_StaticTerminals) (
|
|
OUT VARIANT * pVariant
|
|
);
|
|
|
|
STDMETHOD (EnumerateStaticTerminals) (
|
|
OUT IEnumTerminal ** ppTerminalEnumerator
|
|
);
|
|
|
|
STDMETHOD (get_DynamicTerminalClasses) (
|
|
OUT VARIANT * pVariant
|
|
);
|
|
|
|
STDMETHOD (EnumerateDynamicTerminalClasses) (
|
|
OUT IEnumTerminalClass ** ppTerminalClassEnumerator
|
|
);
|
|
|
|
STDMETHOD (CreateTerminal) (
|
|
IN BSTR pTerminalClass,
|
|
IN long lMediaType,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
OUT ITTerminal ** ppTerminal
|
|
);
|
|
|
|
STDMETHOD (GetDefaultStaticTerminal) (
|
|
IN long lMediaType,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
OUT ITTerminal ** ppTerminal
|
|
);
|
|
|
|
STDMETHOD (get_PluggableSuperclasses)(
|
|
OUT VARIANT * pVariant
|
|
);
|
|
|
|
STDMETHOD (EnumeratePluggableSuperclasses)(
|
|
OUT IEnumPluggableSuperclassInfo** ppSuperclassEnumerator
|
|
);
|
|
|
|
STDMETHOD (get_PluggableTerminalClasses)(
|
|
IN BSTR bstrTerminalSuperclass,
|
|
IN long lMediaType,
|
|
OUT VARIANT * pVariant
|
|
);
|
|
|
|
STDMETHOD (EnumeratePluggableTerminalClasses)(
|
|
IN CLSID iidTerminalSuperclass,
|
|
IN long lMediaType,
|
|
OUT IEnumPluggableTerminalClassInfo ** ppClassEnumerator
|
|
);
|
|
|
|
|
|
protected:
|
|
// ITTerminalSupport helper methods
|
|
|
|
virtual HRESULT GetStaticTerminals (
|
|
IN OUT DWORD * pdwNumTerminals,
|
|
OUT ITTerminal ** ppTerminals
|
|
);
|
|
|
|
virtual HRESULT GetDynamicTerminalClasses (
|
|
IN OUT DWORD * pdwNumClasses,
|
|
OUT IID * pTerminalClasses
|
|
);
|
|
|
|
public:
|
|
// methods used by the MSPCall object.
|
|
|
|
//
|
|
// Check to see if the mediatype is non-zero and is in the mask.
|
|
// Your MSP can override this if it needs to do special checks on
|
|
// specific combinations of media types (e.g., can never have more
|
|
// than one media type on a call, can never have video without
|
|
// audio, etc.) The default implementation accepts any nonempty
|
|
// set of media types that is a subset of the set of all supported
|
|
// media types (specified via the GetCallMediaTypes method).
|
|
//
|
|
virtual BOOL IsValidSetOfMediaTypes(DWORD dwMediaType, DWORD dwMask);
|
|
|
|
// Note: the eventItem must be allocated by malloc or new
|
|
// (when the event is processed, it is deleted).
|
|
virtual HRESULT PostEvent(
|
|
IN MSPEVENTITEM * EventItem
|
|
);
|
|
|
|
// method used by template function
|
|
|
|
virtual DWORD GetCallMediaTypes(void) = 0;
|
|
|
|
protected:
|
|
|
|
// Private helper function (protected so derived class can call it)
|
|
|
|
virtual HRESULT IsMonikerInTerminalList(IMoniker* pMoniker);
|
|
|
|
virtual HRESULT UpdateTerminalListForPnp(
|
|
IN BOOL bDeviceArrival
|
|
);
|
|
|
|
virtual HRESULT UpdateTerminalList(void);
|
|
|
|
virtual HRESULT ReceiveTSPAddressData(
|
|
IN PBYTE pBuffer,
|
|
IN DWORD dwSize
|
|
);
|
|
|
|
public:
|
|
// methods used by the MSPThread object.
|
|
|
|
virtual HRESULT PnpNotifHandler(
|
|
IN BOOL bDeviceArrival
|
|
);
|
|
|
|
protected:
|
|
|
|
// The handle to TAPI's event, which is used to notify TAPI that the MSP
|
|
// wants to send data to it.
|
|
HANDLE m_htEvent;
|
|
|
|
// List of events.
|
|
LIST_ENTRY m_EventList;
|
|
|
|
// The lock that protects the data related to event handling with TAPI.
|
|
CMSPCritSection m_EventDataLock;
|
|
|
|
|
|
// The pointer to the terminal manager object.
|
|
ITTerminalManager * m_pITTerminalManager;
|
|
|
|
// The list of static terminals that can be used on the address.
|
|
CMSPArray <ITTerminal *> m_Terminals;
|
|
BOOL m_fTerminalsUpToDate;
|
|
|
|
// The lock that protects the data members for terminal operations.
|
|
CMSPCritSection m_TerminalDataLock;
|
|
|
|
private:
|
|
static const STATIC_TERMINAL_TYPE m_saTerminalTypes[];
|
|
static const DWORD m_sdwTerminalTypesCount;
|
|
};
|
|
|
|
template <class T>
|
|
HRESULT CreateMSPCallHelper(
|
|
IN CMSPAddress * pCMSPAddress,
|
|
IN MSP_HANDLE htCall,
|
|
IN DWORD dwReserved,
|
|
IN DWORD dwMediaType,
|
|
IN IUnknown * pOuterUnknown,
|
|
OUT IUnknown ** ppMSPCall,
|
|
OUT T ** ppCMSPCall
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CreateMSPCallHelper - enter"));
|
|
|
|
HRESULT hr;
|
|
T * pMSPCall;
|
|
IUnknown *pUnknown = NULL;
|
|
|
|
//
|
|
// Check parameters.
|
|
//
|
|
|
|
if ( IsBadReadPtr(pCMSPAddress, sizeof(CMSPAddress) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"bad address pointer - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( IsBadReadPtr(pOuterUnknown, sizeof(IUnknown) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"bad outer unknown - we require aggregation - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( IsBadReadPtr(ppMSPCall, sizeof(IUnknown *) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"bad iunknown return ptr - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( IsBadReadPtr(ppCMSPCall, sizeof(T *) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"bad class return ptr - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( ! pCMSPAddress->IsValidSetOfMediaTypes(
|
|
dwMediaType,
|
|
pCMSPAddress->GetCallMediaTypes() ) )
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"unsupported media types - exit TAPI_E_INVALIDMEDIATYPE"));
|
|
|
|
return TAPI_E_INVALIDMEDIATYPE;
|
|
}
|
|
|
|
// dwReserved is meaningless.
|
|
// We have no way of checking htCall.
|
|
|
|
// the pOuterUnknown is not NULL. This object is going to be aggregated.
|
|
CComAggObject<T> * pCall;
|
|
|
|
pCall = new CComAggObject<T>(pOuterUnknown);
|
|
|
|
if (pCall == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"could not create agg call instance - exit E_OUTOFMEMORY"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// query the interface on the containing object.
|
|
hr = pCall->QueryInterface(IID_IUnknown, (void **)&pUnknown);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"QueryInterface failed: %x", hr));
|
|
|
|
delete pCall;
|
|
return hr;
|
|
}
|
|
|
|
hr = pCall->FinalConstruct();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"FinalConstruct failed: %x.", hr));
|
|
|
|
pUnknown->Release();
|
|
return hr;
|
|
}
|
|
|
|
// Get a pointer to the real MSPCall object.
|
|
pMSPCall = dynamic_cast<T *>(&(pCall->m_contained));
|
|
if (pMSPCall == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"can not cast to agg object to class pointer - "
|
|
"exit E_UNEXPECTED"));
|
|
|
|
pUnknown->Release();
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// initialize the call.
|
|
//
|
|
|
|
hr = pMSPCall->Init(pCMSPAddress, htCall, dwReserved, dwMediaType);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CreateMSPCallHelper - "
|
|
"call init failed: %x", hr));
|
|
|
|
pUnknown->Release();
|
|
return hr;
|
|
}
|
|
|
|
*ppMSPCall = pUnknown;
|
|
*ppCMSPCall = pMSPCall;
|
|
|
|
LOG((MSP_TRACE, "CreateMSPCallHelper - exit S_OK"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT ShutdownMSPCallHelper(
|
|
IN IUnknown * pUnknown,
|
|
OUT T ** ppCMSPCall
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "ShutdownMSPCallHelper - enter"));
|
|
|
|
if ( IsBadReadPtr(pUnknown, sizeof(IUnknown) ) )
|
|
{
|
|
LOG((MSP_ERROR, "ShutdownMSPCallHelper - "
|
|
"bad IUnknown pointer - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( IsBadWritePtr(ppCMSPCall, sizeof(T *) ) )
|
|
{
|
|
LOG((MSP_ERROR, "ShutdownMSPCallHelper - "
|
|
"bad return pointer - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
T * pMSPCall;
|
|
|
|
CComAggObject<T> * pCall = dynamic_cast<CComAggObject<T> *> (pUnknown);
|
|
|
|
if (pCall == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "ShutdownMSPCallHelper - "
|
|
"can't cast unknown to agg object pointer - exit E_UNEXPECTED"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// It was aggregated. Get a pointer to the real MSPCall object.
|
|
//
|
|
|
|
pMSPCall = dynamic_cast<T *> (&(pCall->m_contained));
|
|
|
|
if (pMSPCall == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "ShutdownMSPCallHelper - "
|
|
"can't cast contained unknown to class pointer - "
|
|
"exit E_UNEXPECTED"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Now we have a call to shut down. Shut it down.
|
|
//
|
|
|
|
HRESULT hr = pMSPCall->ShutDown();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "ShutdownMSPCallHelper - "
|
|
"ShutDownMSPCall failed: %x", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppCMSPCall = pMSPCall;
|
|
|
|
LOG((MSP_TRACE, "ShutdownMSPCallHelper - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#endif //__MSPADDRESS_H_
|