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.

591 lines
18 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 2000
  5. *
  6. * File: mmcaxwin.cpp
  7. *
  8. * Contents: functions for CMMCAxWindow
  9. *
  10. * History: 27-Jan-2000 audriusz Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "stdafx.h"
  14. #include "mshtml.h"
  15. #include "amc.h"
  16. #include "ocxview.h"
  17. #include "amcview.h"
  18. #include "findview.h"
  19. #ifdef DBG
  20. CTraceTag tagMMCViewBehavior (TEXT("MMCView Behavior"), TEXT("MMCView Behavior"));
  21. #endif
  22. /***************************************************************************\
  23. *
  24. * METHOD: CMMCAxHostWindow::Invoke
  25. *
  26. * PURPOSE: ATL 3.0 has a bug in type library so we owerride this method to
  27. * take care of properties which will fail othervise
  28. *
  29. * PARAMETERS:
  30. * DISPID dispIdMember
  31. * REFIID riid
  32. * LCID lcid
  33. * WORD wFlags
  34. * DISPPARAMS FAR* pDispParams
  35. * VARIANT FAR* pVarResult
  36. * EXCEPINFO FAR* pExcepInfo
  37. * unsigned int FAR* puArgErr
  38. *
  39. * RETURNS:
  40. * HRESULT - result code
  41. *
  42. \***************************************************************************/
  43. STDMETHODIMP CMMCAxHostWindow::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr)
  44. {
  45. DECLARE_SC(sc, TEXT("CMMCAxHostWindow::Invoke"));
  46. // This method is here to override IDispatch::Invoke from IDispatchImpl<IAxWinAmbientDispatch,..>
  47. // to workaround the ATL30 bug - invalid type library entries for disp ids:
  48. // DISPID_AMBIENT_SHOWHATCHING and DISPID_AMBIENT_SHOWGRABHANDLES
  49. // Added to solve bug 453609 MMC2.0: ActiveX container: Painting problems with the device manager control
  50. if (DISPATCH_PROPERTYGET & wFlags)
  51. {
  52. if (dispIdMember == DISPID_AMBIENT_SHOWGRABHANDLES)
  53. {
  54. if (pVarResult == NULL)
  55. {
  56. sc = SC(E_INVALIDARG);
  57. return sc.ToHr();
  58. }
  59. V_VT(pVarResult) = VT_BOOL;
  60. sc = get_ShowGrabHandles(&(V_BOOL(pVarResult)));
  61. return sc.ToHr();
  62. }
  63. else if (dispIdMember == DISPID_AMBIENT_SHOWHATCHING)
  64. {
  65. if (pVarResult == NULL)
  66. {
  67. sc = SC(E_INVALIDARG);
  68. return sc.ToHr();
  69. }
  70. V_VT(pVarResult) = VT_BOOL;
  71. sc = get_ShowHatching(&(V_BOOL(pVarResult)));
  72. return sc.ToHr();
  73. }
  74. }
  75. // default: forward to base class
  76. return CAxHostWindow::Invoke( dispIdMember, riid, lcid, wFlags, pDispParams,
  77. pVarResult, pExcepInfo, puArgErr);
  78. }
  79. /***************************************************************************\
  80. *
  81. * METHOD: CMMCAxHostWindow::OnPosRectChange
  82. *
  83. * PURPOSE: ATL does not implement this method, but it's needed to size MFC controls
  84. *
  85. * PARAMETERS:
  86. * LPCRECT lprcPosRect - rectangle to fit in
  87. *
  88. * RETURNS:
  89. * HRESULT - result code
  90. *
  91. \***************************************************************************/
  92. STDMETHODIMP CMMCAxHostWindow::OnPosRectChange(LPCRECT lprcPosRect)
  93. {
  94. DECLARE_SC(sc, TEXT("CMMCAxHostWindow::OnPosRectChange"));
  95. // give base class a try (use temp sc to prevent tracing here)
  96. SC sc_temp = CAxHostWindow::OnPosRectChange(lprcPosRect);
  97. // we only want to come into the game as the last resort
  98. if (!(sc_temp == SC(E_NOTIMPL)))
  99. return sc_temp.ToHr();
  100. // Added to solve bug 453609 MMC2.0: ActiveX container: Painting problems with the device manager control
  101. // since ATL does not implement it, we have to do it to make MFC controls happy
  102. // from MSDN:
  103. // When the in-place object calls IOleInPlaceSite::OnPosRectChange,
  104. // the container must call IOleInPlaceObject::SetObjectRects to specify
  105. // the new position of the in-place window and the ClipRect.
  106. // Only then does the object resize its window.
  107. // get pointer to control
  108. IDispatchPtr spExtendedControl;
  109. sc= GetExtendedControl(&spExtendedControl);
  110. if (sc)
  111. return sc.ToHr();
  112. // get inplace object interface
  113. IOleInPlaceObjectPtr spInPlaceObject = spExtendedControl;
  114. if (spInPlaceObject == NULL)
  115. {
  116. sc = SC(E_UNEXPECTED);
  117. return sc.ToHr();
  118. }
  119. sc = spInPlaceObject->SetObjectRects(lprcPosRect,lprcPosRect);
  120. if (sc)
  121. return sc.ToHr();
  122. return sc.ToHr();
  123. }
  124. /***************************************************************************\
  125. *
  126. * METHOD: CMMCAxHostWindow::OnSetFocus
  127. *
  128. * PURPOSE: Simple override of bogus CAxHostWindow::OnSetFocus
  129. * Coppied from ATL 3.0, changed m_bInPlaceActive to m_bUIActive
  130. * See bug 433228 (MMC2.0 Can not tab in a SQL table)
  131. *
  132. * PARAMETERS:
  133. * UINT uMsg
  134. * WPARAM wParam
  135. * LPARAM lParam
  136. * BOOL& bHandled
  137. *
  138. * RETURNS:
  139. * SC - result code
  140. *
  141. \***************************************************************************/
  142. LRESULT CMMCAxHostWindow::OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  143. {
  144. m_bHaveFocus = TRUE;
  145. if (!m_bReleaseAll)
  146. {
  147. if (m_spOleObject != NULL && !m_bUIActive)
  148. {
  149. CComPtr<IOleClientSite> spClientSite;
  150. GetControllingUnknown()->QueryInterface(IID_IOleClientSite, (void**)&spClientSite);
  151. if (spClientSite != NULL)
  152. {
  153. Trace (tagOCXActivation, _T("Activating in-place object"));
  154. HRESULT hr = m_spOleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, spClientSite, 0, m_hWnd, &m_rcPos);
  155. Trace (tagOCXActivation, _T("UI activation returned 0x%08x"), hr);
  156. }
  157. }
  158. if(!m_bWindowless && !IsChild(::GetFocus()))
  159. {
  160. Trace (tagOCXActivation, _T("Manually setting focus to first child"));
  161. ::SetFocus(::GetWindow(m_hWnd, GW_CHILD));
  162. }
  163. }
  164. else
  165. Trace (tagOCXActivation, _T("Skipping UI activation"));
  166. /*
  167. * The code above might cause the focus to be sent elsewhere, which
  168. * means this window will receive WM_KILLFOCUS. CAxHostWindow::OnKillFocus
  169. * sets m_bHaveFocus to FALSE.
  170. *
  171. * If we set bHandled = FALSE here, then ATL will call CAxHostWindow::OnSetFocus,
  172. * which will set m_bHaveFocus to TRUE again, even though we've already
  173. * lost the focus. We only want to forward on to CAxHostWindow if
  174. * we still have the focus after attempting to activate our hosted control.
  175. */
  176. if (m_bHaveFocus)
  177. {
  178. Trace (tagOCXActivation, _T("Forwarding to CAxHostWindow::OnSetFocus"));
  179. bHandled = FALSE;
  180. }
  181. else
  182. Trace (tagOCXActivation, _T("Skipping CAxHostWindow::OnSetFocus"));
  183. return 0;
  184. }
  185. /*+-------------------------------------------------------------------------*
  186. * class CMMCViewBehavior
  187. *
  188. *
  189. * PURPOSE: Allows the current snapin view (ie list, web, or OCX) to be
  190. * superimposed onto a view extension. The behavior can be attached
  191. * to any tag, and will cause the snapin view to display in the area
  192. * occupied by the tag.
  193. *
  194. *+-------------------------------------------------------------------------*/
  195. class CMMCViewBehavior :
  196. public CComObjectRoot,
  197. public IElementBehavior,
  198. public IDispatch // used as the event sink
  199. {
  200. typedef CMMCViewBehavior ThisClass;
  201. UINT m_bCausalityCount;
  202. // fix to the bug #248351 - ntbug9. 6/25/01 "No List" taskpad displays a list when node selection changes from extended view
  203. // the script should not force the list to be shown more then once, since, due to the asynchronous nature of the
  204. // script execution, some of code may be executed late, after the MMC hides the listview.
  205. // In such case showing the listview is harmful
  206. bool m_bShowShowListView;
  207. public:
  208. BEGIN_COM_MAP(ThisClass)
  209. COM_INTERFACE_ENTRY(IElementBehavior)
  210. COM_INTERFACE_ENTRY(IDispatch) // NEEDED. See note above
  211. END_COM_MAP()
  212. DECLARE_NOT_AGGREGATABLE(ThisClass)
  213. // constructor
  214. CMMCViewBehavior() : m_pAMCView(NULL), m_bCausalityCount(0), m_bShowShowListView(true) {}
  215. // IElementBehavior
  216. STDMETHODIMP Detach() {return ScDetach().ToHr();}
  217. STDMETHODIMP Init(IElementBehaviorSite *pBehaviorSite) {return ScInit(pBehaviorSite).ToHr();}
  218. STDMETHODIMP Notify(LONG lEvent,VARIANT *pVar) {return ScNotify(lEvent).ToHr();}
  219. // IDispatch
  220. STDMETHODIMP GetTypeInfoCount(unsigned int * pctinfo) {return E_NOTIMPL;}
  221. STDMETHODIMP GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo ** ppTInfo) {return E_NOTIMPL;}
  222. STDMETHODIMP GetIDsOfNames( REFIID riid, OLECHAR **rgszNames, unsigned int cNames, LCID lcid, DISPID * rgDispId){return E_NOTIMPL;}
  223. STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
  224. EXCEPINFO *pExcepInfo, unsigned int *puArgErr) {return ScUpdateMMCView().ToHr();}
  225. private:
  226. /*+-------------------------------------------------------------------------*
  227. *
  228. * ScNotify
  229. *
  230. * PURPOSE: Handles the IElementBehavior::Notify method.
  231. * When we get the document ready notification we can get the document
  232. * and get the CAMCView window which will be cached for future use.
  233. *
  234. * PARAMETERS:
  235. * LONG lEvent :
  236. *
  237. * RETURNS:
  238. * SC
  239. *
  240. *+-------------------------------------------------------------------------*/
  241. SC ScNotify(LONG lEvent)
  242. {
  243. DECLARE_SC(sc, TEXT("CMMCViewBehavior::ScNotify"));
  244. // When the whole document is loaded access it to get the CAMCView window.
  245. if (lEvent == BEHAVIOREVENT_DOCUMENTREADY )
  246. {
  247. // get the HTML document from the element
  248. IDispatchPtr spDispatchDoc;
  249. sc = m_spElement->get_document(&spDispatchDoc);
  250. if(sc)
  251. return sc;
  252. // QI for the IOleWindow interface
  253. IOleWindowPtr spOleWindow = spDispatchDoc;
  254. sc = ScCheckPointers(spOleWindow, E_UNEXPECTED);
  255. if(sc)
  256. return sc;
  257. // Get the IE window and find the ancestor AMCView
  258. HWND hwnd = NULL;
  259. sc = spOleWindow->GetWindow(&hwnd);
  260. if(sc)
  261. return sc;
  262. hwnd = FindMMCView(hwnd); // find the ancestor mmcview
  263. if(hwnd==NULL)
  264. return (sc = E_UNEXPECTED);
  265. m_pAMCView = dynamic_cast<CAMCView *>(CWnd::FromHandle(hwnd));
  266. sc = ScCheckPointers(m_pAMCView); // make sure we found a valid view.
  267. if (sc)
  268. return sc;
  269. }
  270. sc = ScUpdateMMCView(); // this sets up the view initially
  271. return sc;
  272. }
  273. /*+-------------------------------------------------------------------------*
  274. *
  275. * ScInit
  276. *
  277. * PURPOSE: Initializes the behavior. Connects the behavior to the onresize
  278. * and onreadystatechange events of the element it is attached to.
  279. * We can talk to the element but cannot access document until we
  280. * get document-ready notification in Notify method.
  281. *
  282. * PARAMETERS:
  283. * IElementBehaviorSite * pBehaviorSite :
  284. *
  285. * RETURNS:
  286. * SC
  287. *
  288. *+-------------------------------------------------------------------------*/
  289. SC ScInit(IElementBehaviorSite *pBehaviorSite)
  290. {
  291. DECLARE_SC(sc, TEXT("CMMCViewBehavior::Init"));
  292. sc = ScCheckPointers(pBehaviorSite);
  293. if(sc)
  294. return sc;
  295. sc = pBehaviorSite->GetElement(&m_spElement);
  296. if(sc)
  297. return sc;
  298. IDispatchPtr spDispatch = this; // does the addref
  299. IHTMLElement2Ptr spElement2 = m_spElement;
  300. sc = ScCheckPointers(spElement2.GetInterfacePtr(), spDispatch.GetInterfacePtr());
  301. if(sc)
  302. return sc;
  303. // set the onresize handler
  304. sc = spElement2->put_onresize(_variant_t(spDispatch.GetInterfacePtr()));
  305. if(sc)
  306. return sc;
  307. // set the onreadystatechange handler
  308. sc = spElement2->put_onreadystatechange(_variant_t(spDispatch.GetInterfacePtr()));
  309. if(sc)
  310. return sc;
  311. return sc;
  312. }
  313. /*+-------------------------------------------------------------------------*
  314. *
  315. * ScDetach
  316. *
  317. * PURPOSE: Detaches the behavior
  318. *
  319. * RETURNS:
  320. * SC
  321. *
  322. *+-------------------------------------------------------------------------*/
  323. SC ScDetach()
  324. {
  325. DECLARE_SC(sc, TEXT("CMMCViewBehavior::ScDetach"));
  326. m_spElement = NULL;
  327. m_pAMCView = NULL;
  328. return sc;
  329. }
  330. /*+-------------------------------------------------------------------------*
  331. * class CCausalityCounter
  332. *
  333. *
  334. * PURPOSE: used to determine whether a function has resulted in a call back to itself on the same stack
  335. *
  336. * USAGE: Initialize with a variable that is set to zero.
  337. *+-------------------------------------------------------------------------*/
  338. class CCausalityCounter //
  339. {
  340. UINT & m_bCounter;
  341. public:
  342. CCausalityCounter(UINT &bCounter) : m_bCounter(bCounter){++m_bCounter;}
  343. ~CCausalityCounter() {--m_bCounter;}
  344. bool HasReentered()
  345. {
  346. return (m_bCounter>1);
  347. }
  348. };
  349. /*+-------------------------------------------------------------------------*
  350. *
  351. * ScUpdateMMCView
  352. *
  353. * PURPOSE: The callback for all events that the behavior is connected to. This
  354. * causes the size of the snapin view to be recomputed and displayed
  355. *
  356. * This method is also called by IDispatch::Invoke, which is called for mouse-in,
  357. * mouse-out events. So this method may be called after Detach in which case
  358. * m_pAMCView is NULL which is legal.
  359. *
  360. * PARAMETERS: None
  361. *
  362. * RETURNS:
  363. * SC
  364. *
  365. *+-------------------------------------------------------------------------*/
  366. SC ScUpdateMMCView()
  367. {
  368. DECLARE_SC(sc, TEXT("CMMCViewBehavior::ScUpdateMMCView"));
  369. CCausalityCounter causalityCounter(m_bCausalityCount);
  370. if(causalityCounter.HasReentered())
  371. return sc; // avoid re-entering the function from itself.
  372. sc = ScCheckPointers(m_spElement);
  373. if(sc)
  374. return sc;
  375. // See the note above.
  376. if (! m_pAMCView)
  377. return sc;
  378. long offsetTop = 0;
  379. long offsetLeft = 0;
  380. long offsetHeight = 0;
  381. long offsetWidth = 0;
  382. // get the coordinates of the element
  383. sc = m_spElement->get_offsetTop(&offsetTop);
  384. if(sc)
  385. return sc;
  386. sc = m_spElement->get_offsetLeft(&offsetLeft);
  387. if(sc)
  388. return sc;
  389. sc = m_spElement->get_offsetHeight(&offsetHeight);
  390. if(sc)
  391. return sc;
  392. sc = m_spElement->get_offsetWidth(&offsetWidth);
  393. if(sc)
  394. return sc;
  395. Trace(tagMMCViewBehavior, TEXT("Top: %d Left: %d Height: %d Width: %d"), offsetTop, offsetLeft, offsetHeight, offsetWidth);
  396. // set the coordinates. NOTE: replace by a single method call
  397. sc = m_pAMCView->ScSetViewExtensionFrame(m_bShowShowListView, offsetTop, offsetLeft, offsetTop + offsetHeight /*bottom*/, offsetLeft + offsetWidth /*right*/);
  398. m_bShowShowListView = false;
  399. return sc;
  400. }
  401. // data members
  402. private:
  403. IHTMLElementPtr m_spElement;
  404. CAMCView * m_pAMCView;
  405. };
  406. /*+-------------------------------------------------------------------------*
  407. * class CElementBehaviorFactory
  408. *
  409. *
  410. * PURPOSE: Creates instances of the MMCView behavior
  411. *
  412. *+-------------------------------------------------------------------------*/
  413. class CElementBehaviorFactory :
  414. public CComObjectRoot,
  415. public IElementBehaviorFactory,
  416. public IObjectSafetyImpl<CElementBehaviorFactory, INTERFACESAFE_FOR_UNTRUSTED_CALLER> // required
  417. {
  418. typedef CElementBehaviorFactory ThisClass;
  419. public:
  420. BEGIN_COM_MAP(ThisClass)
  421. COM_INTERFACE_ENTRY(IElementBehaviorFactory)
  422. COM_INTERFACE_ENTRY(IObjectSafety)
  423. END_COM_MAP()
  424. public: // IElementBehaviorFactory
  425. STDMETHODIMP FindBehavior(BSTR bstrBehavior, BSTR bstrBehaviorUrl,
  426. IElementBehaviorSite *pSite, IElementBehavior **ppBehavior)
  427. {
  428. DECLARE_SC(sc, TEXT("CElementBehaviorFactory::FindBehavior"));
  429. sc = ScCheckPointers(ppBehavior);
  430. if(sc)
  431. return sc.ToHr();
  432. // init out parameter
  433. *ppBehavior = NULL;
  434. if((bstrBehavior != NULL) && (wcscmp(bstrBehavior, L"mmcview")==0)) // requested the mmcview behavior
  435. {
  436. typedef CComObject<CMMCViewBehavior> t_behavior;
  437. t_behavior *pBehavior = NULL;
  438. sc = t_behavior::CreateInstance(&pBehavior);
  439. if(sc)
  440. return sc.ToHr();
  441. *ppBehavior = pBehavior;
  442. if(!*ppBehavior)
  443. {
  444. delete pBehavior;
  445. return (sc = E_UNEXPECTED).ToHr();
  446. }
  447. (*ppBehavior)->AddRef(); // addref for client
  448. return sc.ToHr();
  449. }
  450. return E_FAIL;
  451. }
  452. };
  453. /*+-------------------------------------------------------------------------*
  454. *
  455. * CMMCAxHostWindow::QueryService
  456. *
  457. * PURPOSE: If called with SID_SElementBehaviorFactory, returns a behavior
  458. * factory that implements the mmcview behavior
  459. *
  460. * PARAMETERS:
  461. * REFGUID rsid :
  462. * REFIID riid :
  463. * void** ppvObj :
  464. *
  465. * RETURNS:
  466. * STDMETHODIMP
  467. *
  468. *+-------------------------------------------------------------------------*/
  469. STDMETHODIMP
  470. CMMCAxHostWindow::QueryService( REFGUID rsid, REFIID riid, void** ppvObj)
  471. {
  472. DECLARE_SC(sc, TEXT("CMMCAxHostWindow::QueryService"));
  473. typedef CAxHostWindow BC;
  474. if(rsid==SID_SElementBehaviorFactory)
  475. {
  476. if(m_spElementBehaviorFactory==NULL)
  477. {
  478. // create the object
  479. typedef CComObject<CElementBehaviorFactory> t_behaviorFactory;
  480. t_behaviorFactory *pBehaviorFactory = NULL;
  481. sc = t_behaviorFactory::CreateInstance(&pBehaviorFactory);
  482. if(sc)
  483. return sc.ToHr();
  484. m_spElementBehaviorFactory = pBehaviorFactory; // does the addref
  485. if(m_spElementBehaviorFactory==NULL)
  486. {
  487. delete pBehaviorFactory;
  488. return (sc = E_UNEXPECTED).ToHr();
  489. }
  490. }
  491. sc = m_spElementBehaviorFactory->QueryInterface(riid, ppvObj);
  492. return sc.ToHr();
  493. }
  494. HRESULT hr = BC::QueryService(rsid, riid, ppvObj);
  495. return hr; // do not want errors from BC to be traced
  496. }