/*++ 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 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, public CComObjectRootEx, 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, public CComObjectRootEx, 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, public ITMSPAddress, public IDispatchImpl { 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 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 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 * pCall; pCall = new CComAggObject(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(&(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 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 * pCall = dynamic_cast *> (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 (&(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_