// DecalRes.h : Declaration of the cDecalRes #ifndef __DECALRES_H_ #define __DECALRES_H_ #include "resource.h" // main symbols ///////////////////////////////////////////////////////////////////////////// // cDecalRes class ATL_NO_VTABLE cDecalRes : public CComObjectRootEx, public CComCoClass, public IDispatchImpl, public IConnectionPoint, public IConnectionPointContainer, public IProvideClassInfo2 { public: cDecalRes() : m_dwNextCookie( 1 ) { } // This object iterates over our one connection // point. class cEnumRes : public CComObjectRootEx, public IEnumConnectionPoints { public: BEGIN_COM_MAP(cEnumRes) COM_INTERFACE_ENTRY(IEnumConnectionPoints) END_COM_MAP() bool m_bEnd; CComPtr< IConnectionPoint > m_pCP; void init( IConnectionPoint *pCP ) { m_pCP = pCP; m_bEnd = false; } public: // IEnumConnectionPoints STDMETHOD(Next)( ULONG cConnections, IConnectionPoint **rgpcn, ULONG *pcFetched ) { if( m_bEnd ) { *pcFetched = 0; return S_FALSE; } if( cConnections == 0 ) { *pcFetched = 0; return S_OK; } m_bEnd = true; *pcFetched = 1; return m_pCP->QueryInterface( rgpcn ); } STDMETHOD(Skip)( ULONG cConnections ) { if( cConnections == 0 ) return S_OK; m_bEnd = true; return S_OK; } STDMETHOD(Reset)() { m_bEnd = false; return S_OK; } STDMETHOD(Clone)(IEnumConnectionPoints **ppNew ) { CComObject< cEnumRes > *pEnum; CComObject< cEnumRes >::CreateInstance( &pEnum ); pEnum->m_pCP = m_pCP; pEnum->m_bEnd = m_bEnd; return pEnum->QueryInterface( IID_IEnumConnectionPoints, reinterpret_cast< void ** >( ppNew ) ); } }; // This object implements the event object - Fire resolves // to dispatching an event to our parent. This object is added // into the namespace of the resource. class cResEvent : public CComObjectRootEx, public IDispatch { public: BEGIN_COM_MAP(cResEvent) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() CComPtr< ITypeInfo > m_pItf; cDecalRes *m_pRes; DISPID m_dispid; HRESULT load( MSXML::IXMLDOMElementPtr &pElement ) { // TODO: load the dispid and Fire paramters and create the temporary typeinfo } public: // IDispatch STDMETHOD(GetTypeInfoCount)( UINT *pctinfo ) { if( pctinfo == NULL ) return E_POINTER; *pctinfo = 1; return S_OK; } STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID, ITypeInfo **ppTI ) { if( iTInfo != 0 ) return E_INVALIDARG; if( ppTI == NULL ) return E_POINTER; return m_pItf->QueryInterface( ppTI ); } STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID, DISPID *rgDispID) { if( rgDispID == NULL || rgszNames == NULL ) // By spec return E_POINTER; if( !::InlineIsEqualGUID( riid, IID_NULL ) ) // By spec return DISP_E_UNKNOWNINTERFACE; static LPOLESTR _szFire = OLESTR( "Fire" ); for( UINT i = 0; i < cNames; ++ i ) { if( ::wcscmp( _szFire, rgszNames[ i ] ) == 0 ) rgDispID[ i ] = 1; else rgDispID[ i ] = -1; } return S_OK; } STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *pArgError ) { // Do all the checks in here if( dispIdMember != 1 ) return DISP_E_MEMBERNOTFOUND; if( !::InlineIsEqualGUID( riid, IID_NULL ) ) return DISP_E_UNKNOWNINTERFACE; if( wFlags != DISPATCH_METHOD ) return DISP_E_MEMBERNOTFOUND; return m_pRes->dispatchEvent( m_dispid, pDispParams, pVarResult, pExcepInfo, pArgError ); } }; // Generated TypeInfo CComPtr< ICreateTypeLib2 > m_pLib; CComPtr< ITypeInfo > m_pCoClass; CComPtr< ICreateTypeInfo > m_pSource; HRESULT GetSourceIID( IID *pIID ) { if( !m_pSource.p ) // Not yet initialized - bad return E_FAIL; CComPtr< ITypeInfo > pTI; HRESULT hRes = m_pSource->QueryInterface( &pTI ); if( FAILED( hRes ) ) return hRes; TYPEATTR *pTA; pTI->GetTypeAttr( &pTA ); *pIID = pTA->guid; pTI->ReleaseTypeAttr( pTA ); return S_OK; } // Connection point members typedef std::deque< std::pair< DWORD, CComPtr< IDispatch > > > cCPList; DWORD m_dwNextCookie; cCPList m_cp; HRESULT dispatchEvent( DISPID nID, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr ) { // We simply pass the invoke on, the event object calling us // will correctly remap the ID. for( cCPList::iterator i = m_cp.begin(); i != m_cp.end(); ++ i ) i->second->Invoke( nID, IID_NULL, 0, DISPATCH_METHOD, pDispParams, pVarResult, pExcepInfo, puArgErr ); return S_OK; } // Series of methods to create the type library HRESULT getLibID( MSXML::IXMLDOMDocumentPtr &pdoc, GUID *pGUID ); bool getTypelibFilename( MSXML::IXMLDOMDocumentPtr &pdoc, BSTR *pbstrFilename ); HRESULT initTypelib( MSXML::IXMLDOMDocumentPtr &pdoc, BSTR strFilename ); HRESULT scanTemplate( MSXML::IXMLDOMElementPtr &ptemp, ITypeInfo **ppCoClass, ITypeInfo **ppSource ); DECLARE_REGISTRY_RESOURCEID(IDR_DECALRES) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(cDecalRes) COM_INTERFACE_ENTRY(IDecalRes) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IConnectionPoint) COM_INTERFACE_ENTRY(IConnectionPointContainer) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2) END_COM_MAP() // IDecalRes public: // IConnectionPointContainer STDMETHOD(EnumConnectionPoints)( IEnumConnectionPoints **ppEnum ) { CComObject< cEnumRes > *pEnum; CComObject< cEnumRes >::CreateInstance( &pEnum ); pEnum->init( this ); return pEnum->QueryInterface( IID_IEnumConnectionPoints, reinterpret_cast< void ** >( ppEnum ) ); } STDMETHOD(FindConnectionPoint)( REFIID iid, IConnectionPoint **ppCP ) { if( ppCP == NULL ) return E_POINTER; IID iidSource; HRESULT hRes = GetSourceIID( &iidSource ); if( FAILED( hRes ) ) return hRes; if( ::InlineIsEqualGUID( iid, GUID_NULL ) || ::InlineIsEqualGUID( iid, iidSource ) ) { // Return the connection point return static_cast< IConnectionPoint * >( this )->QueryInterface( ppCP ); } // Not found (duh, it's not the only connection) return CONNECT_E_NOCONNECTION; } // IConnectionPoint STDMETHOD(GetConnectionInterface)( IID *piid ) { if( piid == NULL ) return E_POINTER; return GetSourceIID( piid ); } STDMETHOD(GetConnectionPointContainer)( IConnectionPointContainer **ppCPC ) { return static_cast< IConnectionPoint * >( this )->QueryInterface( ppCPC ); } STDMETHOD(Advise)(IUnknown *pUnk, DWORD *pdwCookie) { if( pdwCookie == NULL || pUnk == NULL ) return E_POINTER; CComPtr< IDispatch > pDisp; HRESULT hRes = pUnk->QueryInterface( &pDisp ); if( FAILED( hRes ) ) return hRes; m_cp.push_back( cCPList::value_type( m_dwNextCookie, pDisp ) ); *pdwCookie = ( m_dwNextCookie ++ ); return S_OK; } STDMETHOD(Unadvise)( DWORD dwCookie ) { // Find the matching cookie for( cCPList::iterator i = m_cp.begin(); i != m_cp.end(); ++ i ) { if( i->first == dwCookie ) { m_cp.erase( i ); return S_OK; } } return CONNECT_E_NOCONNECTION; } STDMETHOD(EnumConnections)(IEnumConnections **) { // We don't support enum'ing connections return E_NOTIMPL; } // IProvideClassInfo STDMETHOD(GetClassInfo)(ITypeInfo **ppTI) { return m_pCoClass->QueryInterface( ppTI ); } // IProvideClassInfo2 STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID *pGUID) { if( dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID ) return E_INVALIDARG; if( pGUID == NULL ) return E_POINTER; return GetSourceIID( pGUID ); } }; #endif //__DECALRES_H_