Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

630 lines
17 KiB

/******************************************************************************
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 );
}