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

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Factory.cpp
  5. Abstract:
  6. This file contains the implementation of the CPCHElementBehaviorFactory class,
  7. which is used to attach binary behaviors to HTML elements.
  8. Revision History:
  9. Davide Massarenti (dmassare) 06/06/2000
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include <mshtmdid.h>
  14. #include <initguid.h>
  15. #include <BehaviorsTypeLib_i.c>
  16. ////////////////////////////////////////////////////////////////////////////////
  17. typedef HRESULT (*pfnBehaviorCreator)( /*[in]*/ CPCHHelpCenterExternal* parent, /*[out]*/ IElementBehavior* *ppBehavior );
  18. template <class T> class BehaviorCreator
  19. {
  20. public:
  21. static HRESULT CreateInstance( /*[in]*/ CPCHHelpCenterExternal* parent, /*[out]*/ IElementBehavior* *ppBehavior )
  22. {
  23. HRESULT hr;
  24. CComObject<T>* obj;
  25. if(SUCCEEDED(hr = obj->CreateInstance( &obj )))
  26. {
  27. obj->AddRef(); obj->Initialize( parent );
  28. hr = obj->QueryInterface( IID_IElementBehavior, (void**)ppBehavior );
  29. obj->Release();
  30. }
  31. return hr;
  32. }
  33. };
  34. struct BehaviorDefinition
  35. {
  36. LPCWSTR szBehaviorName;
  37. LPCWSTR szTagName;
  38. pfnBehaviorCreator pfnCreator;
  39. };
  40. static const BehaviorDefinition s_Behaviors[] =
  41. {
  42. // { NULL , L"A", BehaviorCreator<CPCHBehavior_A> ::CreateInstance },
  43. { L"pch_body" , NULL, BehaviorCreator<CPCHBehavior_BODY> ::CreateInstance },
  44. { L"pch_context" , NULL, BehaviorCreator<CPCHBehavior_CONTEXT> ::CreateInstance },
  45. { L"pch_events" , NULL, BehaviorCreator<CPCHBehavior_EVENT> ::CreateInstance },
  46. { L"pch_handle" , NULL, BehaviorCreator<CPCHBehavior_HANDLE> ::CreateInstance },
  47. { L"pch_hyperlink" , NULL, BehaviorCreator<CPCHBehavior_A> ::CreateInstance },
  48. { L"pch_state" , NULL, BehaviorCreator<CPCHBehavior_STATE> ::CreateInstance },
  49. { L"pch_subsite" , NULL, BehaviorCreator<CPCHBehavior_SUBSITE> ::CreateInstance },
  50. { L"pch_tree" , NULL, BehaviorCreator<CPCHBehavior_TREE> ::CreateInstance },
  51. ////////////////////////////////////////////////////////////////////////////////////////
  52. { L"pch_gradient" , NULL, BehaviorCreator<CPCHBehavior_GRADIENT>::CreateInstance },
  53. { L"pch_bitmap" , NULL, BehaviorCreator<CPCHBehavior_BITMAP> ::CreateInstance },
  54. };
  55. ////////////////////////////////////////////////////////////////////////////////
  56. CPCHElementBehaviorFactory::CPCHElementBehaviorFactory()
  57. {
  58. m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
  59. }
  60. void CPCHElementBehaviorFactory::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent )
  61. {
  62. m_parent = parent;
  63. }
  64. /////////////////////////////////////////////////////////////////////////////
  65. STDMETHODIMP CPCHElementBehaviorFactory::QueryService( REFGUID guidService, REFIID riid, void **ppv )
  66. {
  67. HRESULT hr = E_NOINTERFACE;
  68. if(InlineIsEqualGUID( riid, IID_IElementBehaviorFactory ))
  69. {
  70. hr = QueryInterface( riid, ppv );
  71. }
  72. else if(InlineIsEqualGUID( riid, IID_IPCHHelpCenterExternal ) && m_parent)
  73. {
  74. *ppv = m_parent; m_parent->AddRef();
  75. hr = S_OK;
  76. }
  77. return hr;
  78. }
  79. STDMETHODIMP CPCHElementBehaviorFactory::FindBehavior( /*[in]*/ BSTR bstrBehavior ,
  80. /*[in]*/ BSTR bstrBehaviorUrl ,
  81. /*[in]*/ IElementBehaviorSite* pSite ,
  82. /*[out]*/ IElementBehavior* *ppBehavior )
  83. {
  84. __HCP_FUNC_ENTRY( "CPCHElementBehaviorFactory::FindBehavior" );
  85. HRESULT hr;
  86. CComPtr<IHTMLElement> pElement;
  87. CComBSTR bstrTagName;
  88. const BehaviorDefinition* pBehaviorDef;
  89. int i;
  90. __MPC_PARAMCHECK_BEGIN(hr)
  91. __MPC_PARAMCHECK_NOTNULL(pSite);
  92. __MPC_PARAMCHECK_POINTER_AND_SET(ppBehavior,NULL);
  93. __MPC_PARAMCHECK_END();
  94. //
  95. // Get tag name.
  96. //
  97. if(SUCCEEDED(pSite->GetElement( &pElement )) && pElement)
  98. {
  99. (void)pElement->get_tagName( &bstrTagName );
  100. }
  101. for(pBehaviorDef=s_Behaviors, i=0; i<ARRAYSIZE(s_Behaviors); i++, pBehaviorDef++)
  102. {
  103. if((pBehaviorDef->szBehaviorName == NULL || (bstrBehavior && !_wcsicmp( pBehaviorDef->szBehaviorName, bstrBehavior ))) &&
  104. (pBehaviorDef->szTagName == NULL || (bstrTagName && !_wcsicmp( pBehaviorDef->szTagName , bstrTagName ))) )
  105. {
  106. __MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorDef->pfnCreator( m_parent, ppBehavior ));
  107. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  108. }
  109. }
  110. hr = E_FAIL;
  111. __HCP_FUNC_CLEANUP;
  112. __HCP_FUNC_EXIT(hr);
  113. }
  114. ////////////////////////////////////////////////////////////////////////////////
  115. ////////////////////////////////////////////////////////////////////////////////
  116. ////////////////////////////////////////////////////////////////////////////////
  117. CPCHBehavior::EventSink::EventSink( CPCHBehavior* parent )
  118. {
  119. m_lRef = 1; // long m_lRef;
  120. //
  121. m_Parent = parent; // CPCHBehavior* m_Parent;
  122. // CComPtr<IDispatch> m_elem;
  123. // CComBSTR m_bstrName;
  124. m_pfn = NULL; // CLASS_METHOD m_pfn;
  125. m_fAttached = false; // bool m_fAttached;
  126. m_idNotifyAs = -1; // DISPID m_idNotifyAs;
  127. }
  128. CPCHBehavior::EventSink::~EventSink()
  129. {
  130. (void)Detach();
  131. }
  132. HRESULT CPCHBehavior::EventSink::Attach()
  133. {
  134. HRESULT hr = S_FALSE;
  135. if(m_fAttached)
  136. {
  137. hr = S_OK;
  138. }
  139. else if(m_elem && m_bstrName)
  140. {
  141. CComDispatchDriver disp ( m_elem );
  142. CComVariant vName( m_bstrName );
  143. CComVariant vDisp( (IDispatch*)this );
  144. CComVariant vRes;
  145. if(SUCCEEDED(hr = disp.Invoke2( DISPID_IHTMLELEMENT2_ATTACHEVENT, &vName, &vDisp, &vRes )))
  146. {
  147. if(vRes.vt == VT_BOOL && vRes.boolVal == VARIANT_TRUE)
  148. {
  149. m_fAttached = true;
  150. }
  151. }
  152. }
  153. return hr;
  154. }
  155. HRESULT CPCHBehavior::EventSink::Detach()
  156. {
  157. HRESULT hr = S_FALSE;
  158. if(m_fAttached == false)
  159. {
  160. hr = S_OK;
  161. }
  162. else if(m_elem && m_bstrName)
  163. {
  164. CComDispatchDriver disp ( m_elem );
  165. CComVariant vName( m_bstrName );
  166. CComVariant vDisp( (IDispatch*)this );
  167. //
  168. // EXTERNAL BUG: if we detach from the events, in a particular situation MSHTML crashes...
  169. //
  170. //if(SUCCEEDED(hr = disp.Invoke2( DISPID_IHTMLELEMENT2_DETACHEVENT, &vName, &vDisp )))
  171. {
  172. m_fAttached = false;
  173. }
  174. }
  175. m_elem.Release();
  176. return hr;
  177. }
  178. ////////////////////////////////////////
  179. STDMETHODIMP_(ULONG) CPCHBehavior::EventSink::AddRef()
  180. {
  181. return ::InterlockedIncrement( &m_lRef );
  182. }
  183. STDMETHODIMP_(ULONG) CPCHBehavior::EventSink::Release()
  184. {
  185. ULONG l = ::InterlockedDecrement( &m_lRef );
  186. if(l == 0) delete this;
  187. return l;
  188. }
  189. STDMETHODIMP CPCHBehavior::EventSink::QueryInterface( REFIID iid, void ** ppvObject )
  190. {
  191. if(ppvObject == NULL) return E_POINTER;
  192. if(InlineIsEqualGUID( iid, IID_IDispatch ))
  193. {
  194. *ppvObject = this; AddRef();
  195. return S_OK;
  196. }
  197. *ppvObject = NULL;
  198. return E_NOINTERFACE;
  199. }
  200. ////////////////////////////////////////
  201. STDMETHODIMP CPCHBehavior::EventSink::GetTypeInfoCount( UINT* pctinfo )
  202. {
  203. return E_NOTIMPL;
  204. }
  205. STDMETHODIMP CPCHBehavior::EventSink::GetTypeInfo( UINT itinfo ,
  206. LCID lcid ,
  207. ITypeInfo* *pptinfo )
  208. {
  209. return E_NOTIMPL;
  210. }
  211. STDMETHODIMP CPCHBehavior::EventSink::GetIDsOfNames( REFIID riid ,
  212. LPOLESTR* rgszNames ,
  213. UINT cNames ,
  214. LCID lcid ,
  215. DISPID* rgdispid )
  216. {
  217. return E_NOTIMPL;
  218. }
  219. STDMETHODIMP CPCHBehavior::EventSink::Invoke( DISPID dispidMember ,
  220. REFIID riid ,
  221. LCID lcid ,
  222. WORD wFlags ,
  223. DISPPARAMS* pdispparams ,
  224. VARIANT* pvarResult ,
  225. EXCEPINFO* pexcepinfo ,
  226. UINT* puArgErr )
  227. {
  228. if(m_Parent && m_pfn)
  229. {
  230. return (m_Parent->*m_pfn)( m_idNotifyAs == -1 ? dispidMember : m_idNotifyAs, pdispparams, pvarResult );
  231. }
  232. else
  233. {
  234. return S_FALSE;
  235. }
  236. }
  237. ////////////////////////////////////////
  238. HRESULT CPCHBehavior::EventSink::CreateInstance( /*[in]*/ CPCHBehavior* parent, /*[out]*/ EventSink*& pObj )
  239. {
  240. pObj = new EventSink( parent );
  241. return (pObj == NULL) ? E_OUTOFMEMORY : S_OK;
  242. }
  243. ////////////////////////////////////////////////////////////////////////////////
  244. CPCHBehavior::CPCHBehavior()
  245. {
  246. m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
  247. //
  248. // CComPtr<IElementBehaviorSiteOM> m_siteOM;
  249. // CComPtr<IHTMLElement> m_elem;
  250. // CComPtr<IHTMLElement2> m_elem2;
  251. // SinkList m_lstEventSinks;
  252. m_fRTL = false; // bool m_fRTL;
  253. m_fTrusted = false; // bool m_fTrusted;
  254. m_fSystem = false; // bool m_fSystem;
  255. }
  256. void CPCHBehavior::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent )
  257. {
  258. m_parent = parent;
  259. }
  260. STDMETHODIMP CPCHBehavior::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite )
  261. {
  262. __HCP_FUNC_ENTRY( "CPCHBehavior::Init" );
  263. HRESULT hr;
  264. __MPC_PARAMCHECK_BEGIN(hr)
  265. __MPC_PARAMCHECK_NOTNULL(m_parent);
  266. __MPC_PARAMCHECK_NOTNULL(pBehaviorSite);
  267. __MPC_PARAMCHECK_END();
  268. Detach();
  269. __MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorSite->QueryInterface( IID_IElementBehaviorSiteOM, (LPVOID*)&m_siteOM ));
  270. __MPC_EXIT_IF_METHOD_FAILS(hr, pBehaviorSite->GetElement ( &m_elem ));
  271. __MPC_EXIT_IF_METHOD_FAILS(hr, m_elem .QueryInterface( &m_elem2 ));
  272. //
  273. // Look for security stuff.
  274. //
  275. {
  276. CComPtr<IHTMLDocument2> doc;
  277. CComPtr<IHTMLDocument3> doc3;
  278. if(SUCCEEDED(MPC::HTML::IDispatch_To_IHTMLDocument2( doc, m_elem )))
  279. {
  280. CComBSTR bstrURL;
  281. CComBSTR bstrDir;
  282. if(SUCCEEDED(doc->get_URL( &bstrURL )))
  283. {
  284. m_fTrusted = m_parent->SecurityManager()->IsUrlTrusted( SAFEBSTR( bstrURL ), &m_fSystem );
  285. }
  286. __MPC_EXIT_IF_METHOD_FAILS(hr, doc.QueryInterface( &doc3 ));
  287. __MPC_EXIT_IF_METHOD_FAILS(hr, doc3->get_dir( &bstrDir ));
  288. m_fRTL = (MPC::StrICmp( bstrDir, L"RTL" ) == 0);
  289. }
  290. }
  291. hr = S_OK;
  292. __HCP_FUNC_CLEANUP;
  293. __HCP_FUNC_EXIT(hr);
  294. }
  295. STDMETHODIMP CPCHBehavior::Notify( /*[in]*/ LONG lEvent, /*[in/out]*/ VARIANT* pVar )
  296. {
  297. int i = 2;
  298. return S_OK;
  299. }
  300. STDMETHODIMP CPCHBehavior::Detach()
  301. {
  302. for(SinkIter it = m_lstEventSinks.begin(); it != m_lstEventSinks.end(); it++)
  303. {
  304. EventSink* obj = *it;;
  305. if(obj)
  306. {
  307. obj->m_Parent = NULL;
  308. obj->Detach ();
  309. obj->Release();
  310. }
  311. }
  312. m_lstEventSinks.clear();
  313. m_siteOM.Release();
  314. m_elem .Release();
  315. m_elem2 .Release();
  316. return S_OK;
  317. }
  318. ////////////////////////////////////////////////////////////////////////////////
  319. HRESULT CPCHBehavior::AttachToEvent( /*[in] */ LPCWSTR szName ,
  320. /*[in] */ CLASS_METHOD pfn ,
  321. /*[in] */ IDispatch* elem ,
  322. /*[out]*/ IDispatch* *pVal ,
  323. /*[in] */ DISPID id )
  324. {
  325. __HCP_FUNC_ENTRY( "CPCHBehavior::AttachToEvent" );
  326. HRESULT hr;
  327. SinkIter it;
  328. EventSink* obj = NULL;
  329. __MPC_EXIT_IF_METHOD_FAILS(hr, obj->CreateInstance( this, obj ));
  330. obj->m_elem = elem ? elem : m_elem2;
  331. obj->m_bstrName = szName;
  332. obj->m_pfn = pfn;
  333. obj->m_idNotifyAs = id;
  334. if(pVal) // Don't attach to the site, simply return the IDispatch interface.
  335. {
  336. *pVal = obj; obj->AddRef();
  337. }
  338. else
  339. {
  340. __MPC_EXIT_IF_METHOD_FAILS(hr, obj->Attach());
  341. }
  342. m_lstEventSinks.push_back( obj ); obj = NULL;
  343. hr = S_OK;
  344. __HCP_FUNC_CLEANUP;
  345. if(obj) obj->Release();
  346. __HCP_FUNC_EXIT(hr);
  347. }
  348. HRESULT CPCHBehavior::AttachToEvents( /*[in] */ const EventDescription* pEvents ,
  349. /*[in] */ CLASS_METHOD pfn ,
  350. /*[in] */ IDispatch* elem )
  351. {
  352. __HCP_FUNC_ENTRY( "CPCHBehavior::AttachToEvents" );
  353. HRESULT hr;
  354. while(pEvents->szName)
  355. {
  356. __MPC_EXIT_IF_METHOD_FAILS(hr, AttachToEvent( pEvents->szName, pfn, elem, NULL, pEvents->id ));
  357. pEvents++;
  358. }
  359. hr = S_OK;
  360. __HCP_FUNC_CLEANUP;
  361. __HCP_FUNC_EXIT(hr);
  362. }
  363. HRESULT CPCHBehavior::CreateEvent( /*[in]*/ LPCWSTR szName, /*[out]*/ LONG& lEventCookie )
  364. {
  365. __HCP_FUNC_ENTRY( "CPCHBehavior::CreateEvent" );
  366. HRESULT hr;
  367. hr = m_siteOM ? m_siteOM->RegisterEvent( CComBSTR( szName ), 0, &lEventCookie ) : E_POINTER;
  368. __HCP_FUNC_EXIT(hr);
  369. }
  370. ////////////////////////////////////////
  371. HRESULT CPCHBehavior::GetEventObject( /*[out]*/ CComPtr<IHTMLEventObj>& ev )
  372. {
  373. return MPC::HTML::GetEventObject( ev, m_elem );
  374. }
  375. HRESULT CPCHBehavior::CreateEventObject( /*[out]*/ CComPtr<IHTMLEventObj>& ev )
  376. {
  377. __HCP_FUNC_ENTRY( "CPCHBehavior::CreateEventObject" );
  378. HRESULT hr;
  379. ev.Release();
  380. hr = m_siteOM ? m_siteOM->CreateEventObject( &ev ) : E_POINTER;
  381. __HCP_FUNC_EXIT(hr);
  382. }
  383. HRESULT CPCHBehavior::FireEvent( /*[in ]*/ IHTMLEventObj* ev, /*[in]*/ LONG lEventCookie )
  384. {
  385. __HCP_FUNC_ENTRY( "CPCHBehavior::FireEvent" );
  386. HRESULT hr;
  387. hr = m_siteOM ? m_siteOM->FireEvent( lEventCookie, ev ) : E_POINTER;
  388. __HCP_FUNC_EXIT(hr);
  389. }
  390. HRESULT CPCHBehavior::FireEvent( /*[in]*/ LONG lEventCookie )
  391. {
  392. __HCP_FUNC_ENTRY( "CPCHBehavior::FireEvent" );
  393. HRESULT hr;
  394. CComPtr<IHTMLEventObj> pEvent;
  395. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEventObject( pEvent ));
  396. __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent ( pEvent, lEventCookie ));
  397. hr = S_OK;
  398. __HCP_FUNC_CLEANUP;
  399. __HCP_FUNC_EXIT(hr);
  400. }
  401. ////////////////////////////////////////
  402. HRESULT CPCHBehavior::CancelEvent( /*[in]*/ IHTMLEventObj* ev, /*[in]*/ VARIANT* pvReturnValue, /*[in]*/ VARIANT_BOOL fCancelBubble )
  403. {
  404. __HCP_FUNC_ENTRY( "CPCHBehavior::CancelEvent" );
  405. HRESULT hr;
  406. CComPtr<IHTMLEventObj> pEvent;
  407. CComVariant vDefault;
  408. if(ev == NULL)
  409. {
  410. __MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( pEvent ));
  411. ev = pEvent;
  412. }
  413. if(pvReturnValue == NULL)
  414. {
  415. vDefault = false;
  416. pvReturnValue = &vDefault;
  417. }
  418. __MPC_EXIT_IF_METHOD_FAILS(hr, ev->put_returnValue ( *pvReturnValue ));
  419. __MPC_EXIT_IF_METHOD_FAILS(hr, ev->put_cancelBubble( fCancelBubble ));
  420. hr = S_OK;
  421. __HCP_FUNC_CLEANUP;
  422. __HCP_FUNC_EXIT(hr);
  423. }
  424. ////////////////////////////////////////////////////////////////////////////////
  425. HRESULT CPCHBehavior::GetEvent_SrcElement( /*[in]*/ CComPtr<IHTMLElement>& elem )
  426. {
  427. __HCP_FUNC_ENTRY( "CPCHBehavior::GetEvent_SrcElement" );
  428. HRESULT hr;
  429. CComPtr<IHTMLEventObj> ev;
  430. elem.Release();
  431. __MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( ev ));
  432. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(elem, ev, srcElement);
  433. hr = S_OK;
  434. __HCP_FUNC_CLEANUP;
  435. __HCP_FUNC_EXIT(hr);
  436. }
  437. ////////////////////////////////////////
  438. HRESULT CPCHBehavior::GetAsVARIANT( /*[in]*/ BSTR value, /*[out, retval]*/ VARIANT *pVal )
  439. {
  440. if(pVal == NULL) return E_POINTER;
  441. ::VariantClear( pVal );
  442. pVal->vt = VT_BSTR;
  443. pVal->bstrVal = ::SysAllocString( value );
  444. return S_OK;
  445. }
  446. HRESULT CPCHBehavior::GetAsVARIANT( /*[in]*/ IDispatch* value, /*[out, retval]*/ VARIANT *pVal )
  447. {
  448. if(pVal == NULL) return E_POINTER;
  449. ::VariantClear( pVal );
  450. if(value)
  451. {
  452. pVal->vt = VT_DISPATCH;
  453. pVal->pdispVal = value; value->AddRef();
  454. }
  455. return S_OK;
  456. }
  457. HRESULT CPCHBehavior::GetAsIDISPATCH( /*[in]*/ IDispatch* value, /*[out, retval]*/ IDispatch* *pVal )
  458. {
  459. return MPC::CopyTo( value, pVal );
  460. }