|
|
/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name: Factory.cpp
Abstract: This file contains the implementation of the CPCHElementBehaviorFactory class, which is used to attach binary behaviors to HTML elements.
Revision History: Davide Massarenti (dmassare) 06/06/2000 created
******************************************************************************/
#include "stdafx.h"
#include <mshtmdid.h>
#include <initguid.h>
#include <BehaviorsTypeLib_i.c>
////////////////////////////////////////////////////////////////////////////////
typedef HRESULT (*pfnBehaviorCreator)( /*[in]*/ CPCHHelpCenterExternal* parent, /*[out]*/ IElementBehavior* *ppBehavior );
template <class T> class BehaviorCreator { public: static HRESULT CreateInstance( /*[in]*/ CPCHHelpCenterExternal* parent, /*[out]*/ IElementBehavior* *ppBehavior ) { HRESULT hr; CComObject<T>* obj;
if(SUCCEEDED(hr = obj->CreateInstance( &obj ))) { obj->AddRef(); obj->Initialize( parent );
hr = obj->QueryInterface( IID_IElementBehavior, (void**)ppBehavior );
obj->Release(); }
return hr; } };
struct BehaviorDefinition { LPCWSTR szBehaviorName; LPCWSTR szTagName; pfnBehaviorCreator pfnCreator; };
static const BehaviorDefinition s_Behaviors[] = { // { NULL , L"A", BehaviorCreator<CPCHBehavior_A> ::CreateInstance },
{ L"pch_body" , NULL, BehaviorCreator<CPCHBehavior_BODY> ::CreateInstance }, { L"pch_context" , NULL, BehaviorCreator<CPCHBehavior_CONTEXT> ::CreateInstance }, { L"pch_events" , NULL, BehaviorCreator<CPCHBehavior_EVENT> ::CreateInstance }, { L"pch_handle" , NULL, BehaviorCreator<CPCHBehavior_HANDLE> ::CreateInstance }, { L"pch_hyperlink" , NULL, BehaviorCreator<CPCHBehavior_A> ::CreateInstance }, { L"pch_state" , NULL, BehaviorCreator<CPCHBehavior_STATE> ::CreateInstance }, { L"pch_subsite" , NULL, BehaviorCreator<CPCHBehavior_SUBSITE> ::CreateInstance }, { L"pch_tree" , NULL, BehaviorCreator<CPCHBehavior_TREE> ::CreateInstance }, ////////////////////////////////////////////////////////////////////////////////////////
{ L"pch_gradient" , NULL, BehaviorCreator<CPCHBehavior_GRADIENT>::CreateInstance }, { L"pch_bitmap" , NULL, BehaviorCreator<CPCHBehavior_BITMAP> ::CreateInstance }, };
////////////////////////////////////////////////////////////////////////////////
CPCHElementBehaviorFactory::CPCHElementBehaviorFactory() { m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
}
void CPCHElementBehaviorFactory::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent ) { m_parent = parent; }
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CPCHElementBehaviorFactory::QueryService( REFGUID guidService, REFIID riid, void **ppv ) { HRESULT hr = E_NOINTERFACE;
if(InlineIsEqualGUID( riid, IID_IElementBehaviorFactory )) { hr = QueryInterface( riid, ppv ); } else if(InlineIsEqualGUID( riid, IID_IPCHHelpCenterExternal ) && m_parent) { *ppv = m_parent; m_parent->AddRef();
hr = S_OK; }
return hr; }
STDMETHODIMP CPCHElementBehaviorFactory::FindBehavior( /*[in]*/ BSTR bstrBehavior , /*[in]*/ BSTR bstrBehaviorUrl , /*[in]*/ IElementBehaviorSite* pSite , /*[out]*/ IElementBehavior* *ppBehavior ) { __HCP_FUNC_ENTRY( "CPCHElementBehaviorFactory::FindBehavior" );
HRESULT hr; CComPtr<IHTMLElement> pElement; CComBSTR bstrTagName; const BehaviorDefinition* pBehaviorDef; int i;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pSite); __MPC_PARAMCHECK_POINTER_AND_SET(ppBehavior,NULL); __MPC_PARAMCHECK_END();
//
// Get tag name.
//
if(SUCCEEDED(pSite->GetElement( &pElement )) && pElement) { (void)pElement->get_tagName( &bstrTagName ); }
for(pBehaviorDef=s_Behaviors, i=0; i<ARRAYSIZE(s_Behaviors); i++, pBehaviorDef++) { if((pBehaviorDef->szBehaviorName == NULL || (bstrBehavior && !_wcsicmp( pBehaviorDef->szBehaviorName, bstrBehavior ))) && (pBehaviorDef->szTagName == NULL || (bstrTagName && !_wcsicmp( pBehaviorDef->szTagName , bstrTagName ))) ) { __MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorDef->pfnCreator( m_parent, ppBehavior ));
__MPC_SET_ERROR_AND_EXIT(hr, S_OK); } }
hr = E_FAIL;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
CPCHBehavior::EventSink::EventSink( CPCHBehavior* parent ) { m_lRef = 1; // long m_lRef;
//
m_Parent = parent; // CPCHBehavior* m_Parent;
// CComPtr<IDispatch> m_elem;
// CComBSTR m_bstrName;
m_pfn = NULL; // CLASS_METHOD m_pfn;
m_fAttached = false; // bool m_fAttached;
m_idNotifyAs = -1; // DISPID m_idNotifyAs;
}
CPCHBehavior::EventSink::~EventSink() { (void)Detach(); }
HRESULT CPCHBehavior::EventSink::Attach() { HRESULT hr = S_FALSE;
if(m_fAttached) { hr = S_OK; } else if(m_elem && m_bstrName) { CComDispatchDriver disp ( m_elem ); CComVariant vName( m_bstrName ); CComVariant vDisp( (IDispatch*)this ); CComVariant vRes;
if(SUCCEEDED(hr = disp.Invoke2( DISPID_IHTMLELEMENT2_ATTACHEVENT, &vName, &vDisp, &vRes ))) { if(vRes.vt == VT_BOOL && vRes.boolVal == VARIANT_TRUE) { m_fAttached = true; } } }
return hr; }
HRESULT CPCHBehavior::EventSink::Detach() { HRESULT hr = S_FALSE;
if(m_fAttached == false) { hr = S_OK; } else if(m_elem && m_bstrName) { CComDispatchDriver disp ( m_elem ); CComVariant vName( m_bstrName ); CComVariant vDisp( (IDispatch*)this );
//
// EXTERNAL BUG: if we detach from the events, in a particular situation MSHTML crashes...
//
//if(SUCCEEDED(hr = disp.Invoke2( DISPID_IHTMLELEMENT2_DETACHEVENT, &vName, &vDisp )))
{ m_fAttached = false; } }
m_elem.Release();
return hr; }
////////////////////////////////////////
STDMETHODIMP_(ULONG) CPCHBehavior::EventSink::AddRef() { return ::InterlockedIncrement( &m_lRef ); }
STDMETHODIMP_(ULONG) CPCHBehavior::EventSink::Release() { ULONG l = ::InterlockedDecrement( &m_lRef );
if(l == 0) delete this;
return l; }
STDMETHODIMP CPCHBehavior::EventSink::QueryInterface( REFIID iid, void ** ppvObject ) { if(ppvObject == NULL) return E_POINTER;
if(InlineIsEqualGUID( iid, IID_IDispatch )) { *ppvObject = this; AddRef(); return S_OK; }
*ppvObject = NULL;
return E_NOINTERFACE; }
////////////////////////////////////////
STDMETHODIMP CPCHBehavior::EventSink::GetTypeInfoCount( UINT* pctinfo ) { return E_NOTIMPL; }
STDMETHODIMP CPCHBehavior::EventSink::GetTypeInfo( UINT itinfo , LCID lcid , ITypeInfo* *pptinfo ) { return E_NOTIMPL; }
STDMETHODIMP CPCHBehavior::EventSink::GetIDsOfNames( REFIID riid , LPOLESTR* rgszNames , UINT cNames , LCID lcid , DISPID* rgdispid ) { return E_NOTIMPL; }
STDMETHODIMP CPCHBehavior::EventSink::Invoke( DISPID dispidMember , REFIID riid , LCID lcid , WORD wFlags , DISPPARAMS* pdispparams , VARIANT* pvarResult , EXCEPINFO* pexcepinfo , UINT* puArgErr ) { if(m_Parent && m_pfn) { return (m_Parent->*m_pfn)( m_idNotifyAs == -1 ? dispidMember : m_idNotifyAs, pdispparams, pvarResult ); } else { return S_FALSE; } }
////////////////////////////////////////
HRESULT CPCHBehavior::EventSink::CreateInstance( /*[in]*/ CPCHBehavior* parent, /*[out]*/ EventSink*& pObj ) { pObj = new EventSink( parent );
return (pObj == NULL) ? E_OUTOFMEMORY : S_OK; }
////////////////////////////////////////////////////////////////////////////////
CPCHBehavior::CPCHBehavior() { m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
//
// CComPtr<IElementBehaviorSiteOM> m_siteOM;
// CComPtr<IHTMLElement> m_elem;
// CComPtr<IHTMLElement2> m_elem2;
// SinkList m_lstEventSinks;
m_fRTL = false; // bool m_fRTL;
m_fTrusted = false; // bool m_fTrusted;
m_fSystem = false; // bool m_fSystem;
}
void CPCHBehavior::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent ) { m_parent = parent; }
STDMETHODIMP CPCHBehavior::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite ) { __HCP_FUNC_ENTRY( "CPCHBehavior::Init" );
HRESULT hr;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(m_parent); __MPC_PARAMCHECK_NOTNULL(pBehaviorSite); __MPC_PARAMCHECK_END();
Detach();
__MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorSite->QueryInterface( IID_IElementBehaviorSiteOM, (LPVOID*)&m_siteOM )); __MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorSite->GetElement ( &m_elem )); __MPC_EXIT_IF_METHOD_FAILS(hr, m_elem .QueryInterface( &m_elem2 ));
//
// Look for security stuff.
//
{ CComPtr<IHTMLDocument2> doc; CComPtr<IHTMLDocument3> doc3;
if(SUCCEEDED(MPC::HTML::IDispatch_To_IHTMLDocument2( doc, m_elem ))) { CComBSTR bstrURL; CComBSTR bstrDir;
if(SUCCEEDED(doc->get_URL( &bstrURL ))) { m_fTrusted = m_parent->SecurityManager()->IsUrlTrusted( SAFEBSTR( bstrURL ), &m_fSystem ); }
__MPC_EXIT_IF_METHOD_FAILS(hr, doc.QueryInterface( &doc3 ));
__MPC_EXIT_IF_METHOD_FAILS(hr, doc3->get_dir( &bstrDir ));
m_fRTL = (MPC::StrICmp( bstrDir, L"RTL" ) == 0); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
STDMETHODIMP CPCHBehavior::Notify( /*[in]*/ LONG lEvent, /*[in/out]*/ VARIANT* pVar ) { int i = 2;
return S_OK; }
STDMETHODIMP CPCHBehavior::Detach() { for(SinkIter it = m_lstEventSinks.begin(); it != m_lstEventSinks.end(); it++) { EventSink* obj = *it;;
if(obj) { obj->m_Parent = NULL; obj->Detach (); obj->Release(); } } m_lstEventSinks.clear();
m_siteOM.Release(); m_elem .Release(); m_elem2 .Release();
return S_OK; }
////////////////////////////////////////////////////////////////////////////////
HRESULT CPCHBehavior::AttachToEvent( /*[in] */ LPCWSTR szName , /*[in] */ CLASS_METHOD pfn , /*[in] */ IDispatch* elem , /*[out]*/ IDispatch* *pVal , /*[in] */ DISPID id ) { __HCP_FUNC_ENTRY( "CPCHBehavior::AttachToEvent" );
HRESULT hr; SinkIter it; EventSink* obj = NULL;
__MPC_EXIT_IF_METHOD_FAILS(hr, obj->CreateInstance( this, obj ));
obj->m_elem = elem ? elem : m_elem2; obj->m_bstrName = szName; obj->m_pfn = pfn; obj->m_idNotifyAs = id;
if(pVal) // Don't attach to the site, simply return the IDispatch interface.
{ *pVal = obj; obj->AddRef(); } else { __MPC_EXIT_IF_METHOD_FAILS(hr, obj->Attach()); }
m_lstEventSinks.push_back( obj ); obj = NULL;
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(obj) obj->Release();
__HCP_FUNC_EXIT(hr); }
HRESULT CPCHBehavior::AttachToEvents( /*[in] */ const EventDescription* pEvents , /*[in] */ CLASS_METHOD pfn , /*[in] */ IDispatch* elem ) { __HCP_FUNC_ENTRY( "CPCHBehavior::AttachToEvents" );
HRESULT hr;
while(pEvents->szName) { __MPC_EXIT_IF_METHOD_FAILS(hr, AttachToEvent( pEvents->szName, pfn, elem, NULL, pEvents->id ));
pEvents++; }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT CPCHBehavior::CreateEvent( /*[in]*/ LPCWSTR szName, /*[out]*/ LONG& lEventCookie ) { __HCP_FUNC_ENTRY( "CPCHBehavior::CreateEvent" );
HRESULT hr;
hr = m_siteOM ? m_siteOM->RegisterEvent( CComBSTR( szName ), 0, &lEventCookie ) : E_POINTER;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT CPCHBehavior::GetEventObject( /*[out]*/ CComPtr<IHTMLEventObj>& ev ) { return MPC::HTML::GetEventObject( ev, m_elem ); }
HRESULT CPCHBehavior::CreateEventObject( /*[out]*/ CComPtr<IHTMLEventObj>& ev ) { __HCP_FUNC_ENTRY( "CPCHBehavior::CreateEventObject" );
HRESULT hr;
ev.Release();
hr = m_siteOM ? m_siteOM->CreateEventObject( &ev ) : E_POINTER;
__HCP_FUNC_EXIT(hr); }
HRESULT CPCHBehavior::FireEvent( /*[in ]*/ IHTMLEventObj* ev, /*[in]*/ LONG lEventCookie ) { __HCP_FUNC_ENTRY( "CPCHBehavior::FireEvent" );
HRESULT hr;
hr = m_siteOM ? m_siteOM->FireEvent( lEventCookie, ev ) : E_POINTER;
__HCP_FUNC_EXIT(hr); }
HRESULT CPCHBehavior::FireEvent( /*[in]*/ LONG lEventCookie ) { __HCP_FUNC_ENTRY( "CPCHBehavior::FireEvent" );
HRESULT hr; CComPtr<IHTMLEventObj> pEvent;
__MPC_EXIT_IF_METHOD_FAILS(hr, CreateEventObject( pEvent )); __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent ( pEvent, lEventCookie ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT CPCHBehavior::CancelEvent( /*[in]*/ IHTMLEventObj* ev, /*[in]*/ VARIANT* pvReturnValue, /*[in]*/ VARIANT_BOOL fCancelBubble ) { __HCP_FUNC_ENTRY( "CPCHBehavior::CancelEvent" );
HRESULT hr; CComPtr<IHTMLEventObj> pEvent; CComVariant vDefault;
if(ev == NULL) { __MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( pEvent ));
ev = pEvent; }
if(pvReturnValue == NULL) { vDefault = false;
pvReturnValue = &vDefault; }
__MPC_EXIT_IF_METHOD_FAILS(hr, ev->put_returnValue ( *pvReturnValue )); __MPC_EXIT_IF_METHOD_FAILS(hr, ev->put_cancelBubble( fCancelBubble ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
HRESULT CPCHBehavior::GetEvent_SrcElement( /*[in]*/ CComPtr<IHTMLElement>& elem ) { __HCP_FUNC_ENTRY( "CPCHBehavior::GetEvent_SrcElement" );
HRESULT hr; CComPtr<IHTMLEventObj> ev;
elem.Release();
__MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( ev ));
MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(elem, ev, srcElement);
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT CPCHBehavior::GetAsVARIANT( /*[in]*/ BSTR value, /*[out, retval]*/ VARIANT *pVal ) { if(pVal == NULL) return E_POINTER;
::VariantClear( pVal );
pVal->vt = VT_BSTR; pVal->bstrVal = ::SysAllocString( value );
return S_OK; }
HRESULT CPCHBehavior::GetAsVARIANT( /*[in]*/ IDispatch* value, /*[out, retval]*/ VARIANT *pVal ) { if(pVal == NULL) return E_POINTER;
::VariantClear( pVal );
if(value) { pVal->vt = VT_DISPATCH; pVal->pdispVal = value; value->AddRef(); }
return S_OK; }
HRESULT CPCHBehavior::GetAsIDISPATCH( /*[in]*/ IDispatch* value, /*[out, retval]*/ IDispatch* *pVal ) { return MPC::CopyTo( value, pVal ); }
|