Leaked source code of windows server 2003
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.

1686 lines
48 KiB

  1. #include "shellprv.h"
  2. // APPCOMPAT (lamadio): Conflicts with one defined in winuserp.h
  3. #undef WINEVENT_VALID //It's tripping on this...
  4. #include "winable.h"
  5. #include "apithk.h"
  6. #include "mnbandid.h"
  7. #include "initguid.h"
  8. #include "iaccess.h"
  9. #include "mluisupp.h"
  10. CAccessible::CAccessible(HMENU hmenu, WORD wID):
  11. _hMenu(hmenu), _wID(wID), _cRef(1)
  12. {
  13. _fState = MB_STATE_TRACK;
  14. }
  15. CAccessible::CAccessible(IMenuBand* pmb): _cRef(1)
  16. {
  17. _fState = MB_STATE_MENU;
  18. _pmb = pmb;
  19. if (_pmb)
  20. {
  21. _pmb->AddRef();
  22. }
  23. }
  24. CAccessible::CAccessible(IMenuBand* pmb, int iIndex): _cRef(1)
  25. {
  26. _fState = MB_STATE_ITEM;
  27. _iAccIndex = iIndex;
  28. _pmb = pmb;
  29. if (_pmb)
  30. {
  31. _pmb->AddRef();
  32. }
  33. }
  34. CAccessible::~CAccessible()
  35. {
  36. ATOMICRELEASE(_pTypeInfo);
  37. ATOMICRELEASE(_pInnerAcc);
  38. switch (_fState)
  39. {
  40. case MB_STATE_TRACK:
  41. ASSERT(!_hwndMenuWindow || IsWindow(_hwndMenuWindow));
  42. if (_hwndMenuWindow)
  43. {
  44. // Don't Destroy hmenu. It's part of a larger one...
  45. SetMenu(_hwndMenuWindow, NULL);
  46. DestroyWindow(_hwndMenuWindow);
  47. _hwndMenuWindow = NULL;
  48. }
  49. break;
  50. case MB_STATE_ITEM:
  51. ATOMICRELEASE(_pmtbItem);
  52. // Fall Through
  53. case MB_STATE_MENU:
  54. ATOMICRELEASE(_pmtbTop);
  55. ATOMICRELEASE(_pmtbBottom);
  56. ATOMICRELEASE(_psma);
  57. ATOMICRELEASE(_pmb);
  58. break;
  59. }
  60. }
  61. HRESULT CAccessible::InitAcc()
  62. {
  63. HRESULT hr = E_FAIL;
  64. if (_fInitialized)
  65. return NOERROR;
  66. _fInitialized = TRUE; // We're initialized if we fail or not...
  67. switch (_fState)
  68. {
  69. case MB_STATE_TRACK:
  70. if (EVAL(_hMenu))
  71. {
  72. _hwndMenuWindow = CreateWindow(TEXT("static"),
  73. TEXT("MenuWindow"), WS_POPUP, 0, 0, 0, 0, NULL,
  74. _hMenu, g_hinst, NULL);
  75. if (EVAL(_hwndMenuWindow))
  76. {
  77. IAccessible* paccChild1;
  78. hr = CreateStdAccessibleObject(_hwndMenuWindow, OBJID_MENU, IID_PPV_ARG(IAccessible, &paccChild1));
  79. if (SUCCEEDED(hr))
  80. {
  81. VARIANT varChild;
  82. varChild.vt = VT_I4;
  83. varChild.lVal = _wID + 1; //Accesibility is 1 based
  84. // In order to get "On par" with the OleAcc's implementation of the HMENU wrapper,
  85. // we need to do this twice. Once gets us the IAccessible for the "MenuItem" on the
  86. // "Menubar". The second gets us the "Menuitem's" child. This is what we need to emulate
  87. // their heirarchy.
  88. IDispatch* pdispChild1;
  89. hr = paccChild1->get_accChild(varChild, &pdispChild1);
  90. // OLEAcc returns a Success code (S_FALSE) while initializing the out param to zero.
  91. // Explicitly test this situation.
  92. // Does this have a Child?
  93. if (hr == S_OK)
  94. {
  95. // Yes. Look for that child
  96. IAccessible* paccChild2;
  97. hr = pdispChild1->QueryInterface(IID_PPV_ARG(IAccessible, &paccChild2));
  98. // Does this have a child?
  99. if (hr == S_OK)
  100. {
  101. // Yep, then we store this guy's child...
  102. IDispatch* pdispChild2;
  103. varChild.lVal = 1; //Get the first child
  104. hr = paccChild2->get_accChild(varChild, &pdispChild2);
  105. if (hr == S_OK)
  106. {
  107. hr = pdispChild2->QueryInterface(IID_PPV_ARG(IAccessible, &_pInnerAcc));
  108. pdispChild2->Release();
  109. }
  110. paccChild2->Release();
  111. }
  112. pdispChild1->Release();
  113. }
  114. paccChild1->Release();
  115. }
  116. }
  117. }
  118. break;
  119. case MB_STATE_ITEM:
  120. case MB_STATE_MENU:
  121. hr = _pmb->QueryInterface(IID_PPV_ARG(IShellMenuAcc, &_psma));
  122. if (SUCCEEDED(hr))
  123. {
  124. _psma->GetTop(&_pmtbTop);
  125. _psma->GetBottom(&_pmtbBottom);
  126. if (!_pmtbTop || !_pmtbBottom)
  127. {
  128. hr = E_FAIL;
  129. }
  130. }
  131. if (SUCCEEDED(hr) && (_fState == MB_STATE_ITEM))
  132. {
  133. VARIANT varChild;
  134. _GetVariantFromChildIndex(NULL, _iAccIndex, &varChild);
  135. if (SUCCEEDED(_GetChildFromVariant(&varChild, &_pmtbItem, &_iIndex)))
  136. _idCmd = GetButtonCmd(_pmtbItem->_hwndMB, _iIndex);
  137. }
  138. break;
  139. }
  140. return hr;
  141. }
  142. /*----------------------------------------------------------
  143. Purpose: IUnknown::AddRef method
  144. */
  145. STDMETHODIMP_(ULONG) CAccessible::AddRef()
  146. {
  147. _cRef++;
  148. return _cRef;
  149. }
  150. /*----------------------------------------------------------
  151. Purpose: IUnknown::Release method
  152. */
  153. STDMETHODIMP_(ULONG) CAccessible::Release()
  154. {
  155. ASSERT(_cRef > 0);
  156. _cRef--;
  157. if (_cRef > 0)
  158. return _cRef;
  159. delete this;
  160. return 0;
  161. }
  162. /*----------------------------------------------------------
  163. Purpose: IUnknown::QueryInterface method
  164. */
  165. STDMETHODIMP CAccessible::QueryInterface(REFIID riid, LPVOID * ppvObj)
  166. {
  167. static const QITAB qit[] =
  168. {
  169. QITABENT(CAccessible, IDispatch),
  170. QITABENT(CAccessible, IAccessible),
  171. QITABENT(CAccessible, IEnumVARIANT),
  172. QITABENT(CAccessible, IOleWindow),
  173. { 0 },
  174. };
  175. return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
  176. }
  177. /*----------------------------------------------------------
  178. Purpose: IDispatch::GetTypeInfoCount method
  179. */
  180. STDMETHODIMP CAccessible::GetTypeInfoCount(UINT * pctinfo)
  181. {
  182. if (_pInnerAcc)
  183. return _pInnerAcc->GetTypeInfoCount(pctinfo);
  184. *pctinfo = 1;
  185. return NOERROR;
  186. }
  187. /*----------------------------------------------------------
  188. Purpose: IDispatch::GetTypeInfo method
  189. */
  190. STDMETHODIMP CAccessible::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo ** pptinfo)
  191. {
  192. *pptinfo = NULL;
  193. if (_pInnerAcc)
  194. return _pInnerAcc->GetTypeInfo(itinfo, lcid, pptinfo);
  195. if (itinfo != 0)
  196. return DISP_E_BADINDEX;
  197. if (EVAL(_LoadTypeLib()))
  198. {
  199. *pptinfo = _pTypeInfo;
  200. _pTypeInfo->AddRef();
  201. return NOERROR;
  202. }
  203. else
  204. return E_FAIL;
  205. }
  206. /*----------------------------------------------------------
  207. Purpose: IDispatch::GetIDsOfNames method
  208. */
  209. STDMETHODIMP CAccessible::GetIDsOfNames(REFIID riid, OLECHAR ** rgszNames, UINT cNames,
  210. LCID lcid, DISPID * rgdispid)
  211. {
  212. if (_pInnerAcc)
  213. return _pInnerAcc->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  214. if (IID_NULL != riid)
  215. return DISP_E_UNKNOWNINTERFACE;
  216. if (EVAL(_LoadTypeLib()))
  217. {
  218. return _pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  219. }
  220. else
  221. return E_FAIL;
  222. }
  223. /*----------------------------------------------------------
  224. Purpose: IDispatch::Invoke method
  225. */
  226. STDMETHODIMP CAccessible::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  227. DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
  228. UINT * puArgErr)
  229. {
  230. if (_pInnerAcc)
  231. return _pInnerAcc->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult,
  232. pexcepinfo, puArgErr);
  233. if (IID_NULL != riid)
  234. return DISP_E_UNKNOWNINTERFACE;
  235. if (EVAL(_LoadTypeLib()))
  236. {
  237. return _pTypeInfo->Invoke(static_cast<IDispatch*>(this),
  238. dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  239. }
  240. else
  241. return E_FAIL;
  242. }
  243. BOOL CAccessible::_LoadTypeLib()
  244. {
  245. ITypeLib* pTypeLib;
  246. if (_pTypeInfo)
  247. return TRUE;
  248. if (SUCCEEDED(LoadTypeLib(L"oleacc.dll", &pTypeLib)))
  249. {
  250. pTypeLib->GetTypeInfoOfGuid(IID_IAccessible, &_pTypeInfo);
  251. ATOMICRELEASE(pTypeLib);
  252. return TRUE;
  253. }
  254. return FALSE;
  255. }
  256. /*----------------------------------------------------------
  257. Purpose: IAccessible::get_accParent method
  258. */
  259. STDMETHODIMP CAccessible::get_accParent(IDispatch ** ppdispParent)
  260. {
  261. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  262. switch (_fState)
  263. {
  264. case MB_STATE_TRACK:
  265. if (_pInnerAcc)
  266. return _pInnerAcc->get_accParent(ppdispParent);
  267. break;
  268. case MB_STATE_MENU:
  269. {
  270. IUnknown* punk;
  271. if (SUCCEEDED(_psma->GetParentSite(IID_PPV_ARG(IUnknown, &punk))))
  272. {
  273. IAccessible* pacc;
  274. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SMenuBandParent,
  275. IID_PPV_ARG(IAccessible, &pacc))))
  276. {
  277. VARIANT varChild = {VT_I4, CHILDID_SELF}; // Init
  278. hr = pacc->get_accFocus(&varChild);
  279. if (SUCCEEDED(hr))
  280. {
  281. hr = pacc->get_accChild(varChild, ppdispParent);
  282. }
  283. VariantClear(&varChild);
  284. pacc->Release();
  285. }
  286. else
  287. {
  288. // Another implementation headache: Accessibility requires
  289. // us to return S_FALSE when there is no parent.
  290. *ppdispParent = NULL;
  291. hr = S_FALSE;
  292. }
  293. punk->Release();
  294. }
  295. return hr;
  296. }
  297. case MB_STATE_ITEM:
  298. // The parent of an item is the menuband itself
  299. return IUnknown_QueryService(_psma, SID_SMenuPopup, IID_PPV_ARG(IDispatch, ppdispParent));
  300. break;
  301. }
  302. return DISP_E_MEMBERNOTFOUND;
  303. }
  304. /*----------------------------------------------------------
  305. Purpose: IAccessible::get_accChildCount method
  306. */
  307. STDMETHODIMP CAccessible::get_accChildCount(long * pChildCount)
  308. {
  309. *pChildCount = 0;
  310. switch (_fState)
  311. {
  312. case MB_STATE_TRACK:
  313. if (_pInnerAcc)
  314. return _pInnerAcc->get_accChildCount(pChildCount);
  315. break;
  316. case MB_STATE_MENU:
  317. {
  318. int iTopCount = ToolBar_ButtonCount(_pmtbTop->_hwndMB);
  319. int iBottomCount = ToolBar_ButtonCount(_pmtbBottom->_hwndMB);
  320. *pChildCount = (_pmtbTop != _pmtbBottom)? iTopCount + iBottomCount : iTopCount;
  321. }
  322. break;
  323. case MB_STATE_ITEM:
  324. if (_pmtbItem->v_GetFlags(_idCmd) & SMIF_SUBMENU)
  325. *pChildCount = 1;
  326. break;
  327. }
  328. return NOERROR;
  329. }
  330. /*----------------------------------------------------------
  331. Purpose: IAccessible::get_accChild method
  332. */
  333. STDMETHODIMP CAccessible::get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild)
  334. {
  335. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  336. switch (_fState)
  337. {
  338. case MB_STATE_TRACK:
  339. if (_pInnerAcc)
  340. return _pInnerAcc->get_accChild(varChildIndex, ppdispChild);
  341. break;
  342. case MB_STATE_MENU:
  343. {
  344. if (varChildIndex.vt == VT_I4 && varChildIndex.lVal == CHILDID_SELF)
  345. {
  346. // So this is the ONLY menthod that is allowed to fail when something is
  347. // unavailable.
  348. *ppdispChild = NULL;
  349. hr = E_INVALIDARG;
  350. }
  351. else
  352. {
  353. int iIndex;
  354. // Since it's returing an index, we don't need to test the success case
  355. _GetChildFromVariant(&varChildIndex, NULL, &iIndex);
  356. hr = _GetAccessibleItem(iIndex, ppdispChild);
  357. }
  358. }
  359. break;
  360. case MB_STATE_ITEM:
  361. if (_pmtbItem->v_GetFlags(_idCmd) & SMIF_SUBMENU)
  362. {
  363. VARIANT varChild;
  364. hr = _GetVariantFromChildIndex(_pmtbItem->_hwndMB, _iIndex, &varChild);
  365. if (SUCCEEDED(hr))
  366. {
  367. hr = _psma->GetSubMenu(&varChild, IID_PPV_ARG(IDispatch, ppdispChild));
  368. if (FAILED(hr))
  369. {
  370. hr = S_FALSE;
  371. }
  372. }
  373. }
  374. else
  375. hr = E_NOINTERFACE;
  376. break;
  377. }
  378. return hr;
  379. }
  380. HRESULT CAccessible::_GetAccName(BSTR* pbstr)
  381. {
  382. IDispatch* pdisp;
  383. HRESULT hr = get_accParent(&pdisp);
  384. // Get parent can return a success code, but still fail to return a parent.
  385. //
  386. if (hr == S_OK)
  387. {
  388. IAccessible* pacc;
  389. hr = pdisp->QueryInterface(IID_PPV_ARG(IAccessible, &pacc));
  390. if (SUCCEEDED(hr))
  391. {
  392. VARIANT varChild;
  393. hr = pacc->get_accFocus(&varChild);
  394. if (SUCCEEDED(hr))
  395. hr = pacc->get_accName(varChild, pbstr);
  396. }
  397. }
  398. return hr;
  399. }
  400. /*----------------------------------------------------------
  401. Purpose: IAccessible::get_accName method
  402. */
  403. STDMETHODIMP CAccessible::get_accName(VARIANT varChild, BSTR* pszName)
  404. {
  405. CMenuToolbarBase* pmtb = _pmtbItem;
  406. int idCmd = _idCmd;
  407. int iIndex = _iIndex;
  408. *pszName = NULL;
  409. switch (_fState)
  410. {
  411. case MB_STATE_TRACK:
  412. if (_pInnerAcc)
  413. return _pInnerAcc->get_accName(varChild, pszName);
  414. break;
  415. case MB_STATE_MENU:
  416. if (varChild.lVal == CHILDID_SELF)
  417. {
  418. if (_GetAccName(pszName) == S_FALSE)
  419. {
  420. TCHAR sz[100];
  421. LoadString(HINST_THISDLL, IDS_ACC_APP, sz, ARRAYSIZE(sz));
  422. *pszName = SysAllocStringT(sz);
  423. if (!*pszName)
  424. return E_OUTOFMEMORY;
  425. }
  426. return NOERROR;
  427. }
  428. else
  429. {
  430. if (FAILED(_GetChildFromVariant(&varChild, &pmtb, &iIndex)))
  431. return DISP_E_MEMBERNOTFOUND;
  432. idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  433. }
  434. // Fall Through
  435. case MB_STATE_ITEM:
  436. {
  437. TCHAR sz[MAX_PATH];
  438. int idString = 0;
  439. TBBUTTON tbb;
  440. if (ToolBar_GetButton(pmtb->_hwndMB, iIndex, &tbb) &&
  441. tbb.fsStyle & BTNS_SEP)
  442. {
  443. idString = IDS_ACC_SEP;
  444. }
  445. else if (pmtb->GetChevronID() == _idCmd)
  446. {
  447. idString = IDS_ACC_CHEVRON;
  448. }
  449. if (idString != 0)
  450. {
  451. LoadString(HINST_THISDLL, idString, sz, ARRAYSIZE(sz));
  452. *pszName = SysAllocStringT(sz);
  453. }
  454. else
  455. {
  456. UINT cch = SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, NULL);
  457. if (cch != 0 && cch < ARRAYSIZE(sz))
  458. {
  459. if (SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, (LPARAM)sz) > 0)
  460. {
  461. SHStripMneumonic(sz);
  462. *pszName = SysAllocString(sz);
  463. }
  464. }
  465. }
  466. if (_fState == MB_STATE_MENU)
  467. pmtb->Release();
  468. if (!*pszName)
  469. return E_OUTOFMEMORY;
  470. return NOERROR;
  471. }
  472. break;
  473. }
  474. return DISP_E_MEMBERNOTFOUND;
  475. }
  476. /*----------------------------------------------------------
  477. Purpose: IAccessible::get_accValue method
  478. */
  479. STDMETHODIMP CAccessible::get_accValue(VARIANT varChild, BSTR* pszValue)
  480. {
  481. switch (_fState)
  482. {
  483. case MB_STATE_TRACK:
  484. if (_pInnerAcc)
  485. return _pInnerAcc->get_accValue(varChild, pszValue);
  486. break;
  487. case MB_STATE_MENU:
  488. case MB_STATE_ITEM:
  489. *pszValue = NULL;
  490. return S_FALSE;
  491. }
  492. return DISP_E_MEMBERNOTFOUND;
  493. }
  494. /*----------------------------------------------------------
  495. Purpose: IAccessible::get_accDescription method
  496. */
  497. STDMETHODIMP CAccessible::get_accDescription(VARIANT varChild, BSTR * pszDescription)
  498. {
  499. switch (_fState)
  500. {
  501. case MB_STATE_TRACK:
  502. if (_pInnerAcc)
  503. return _pInnerAcc->get_accDescription(varChild, pszDescription);
  504. break;
  505. case MB_STATE_MENU:
  506. if (FAILED(_GetAccName(pszDescription)))
  507. {
  508. TCHAR sz[100];
  509. LoadString(HINST_THISDLL, IDS_ACC_APPMB, sz, ARRAYSIZE(sz));
  510. *pszDescription = SysAllocStringT(sz);
  511. if (!*pszDescription)
  512. return E_OUTOFMEMORY;
  513. }
  514. break;
  515. case MB_STATE_ITEM:
  516. return get_accName(varChild, pszDescription);
  517. break;
  518. }
  519. return DISP_E_MEMBERNOTFOUND;
  520. }
  521. /*----------------------------------------------------------
  522. Purpose: IAccessible::get_accRole method
  523. */
  524. STDMETHODIMP CAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  525. {
  526. pvarRole->vt = VT_I4;
  527. switch (_fState)
  528. {
  529. case MB_STATE_TRACK:
  530. if (_pInnerAcc)
  531. return _pInnerAcc->get_accRole(varChild, pvarRole);
  532. break;
  533. case MB_STATE_MENU:
  534. {
  535. BOOL fVertical, fOpen;
  536. _psma->GetState(&fVertical, &fOpen);
  537. pvarRole->lVal = fVertical ? ROLE_SYSTEM_MENUPOPUP : ROLE_SYSTEM_MENUBAR;
  538. return NOERROR;
  539. }
  540. case MB_STATE_ITEM:
  541. pvarRole->lVal = ROLE_SYSTEM_MENUITEM;
  542. return NOERROR;
  543. }
  544. return DISP_E_MEMBERNOTFOUND;
  545. }
  546. /*----------------------------------------------------------
  547. Purpose: IAccessible::get_accState method
  548. */
  549. STDMETHODIMP CAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
  550. {
  551. switch (_fState)
  552. {
  553. case MB_STATE_TRACK:
  554. if (_pInnerAcc)
  555. return _pInnerAcc->get_accState(varChild, pvarState);
  556. break;
  557. case MB_STATE_MENU:
  558. {
  559. // All menus can be selected, and given focus. Most will be visible.
  560. DWORD dwState = STATE_SYSTEM_FOCUSABLE;
  561. BOOL fOpen, fVertical;
  562. _psma->GetState(&fVertical, &fOpen);
  563. // Do we have a menu popped up?
  564. if (fOpen)
  565. {
  566. // Yes, then we have focus
  567. dwState |= STATE_SYSTEM_FOCUSED;
  568. }
  569. else if (fVertical)
  570. {
  571. // If we're a vertical menu without being popped up, then we're invisible.
  572. dwState |= STATE_SYSTEM_INVISIBLE;
  573. }
  574. pvarState->vt = VT_I4;
  575. pvarState->lVal = dwState;
  576. }
  577. return NOERROR;
  578. case MB_STATE_ITEM:
  579. {
  580. DWORD dwState = 0;
  581. TBBUTTON tbb;
  582. if (-1 != ToolBar_GetButton(_pmtbItem->_hwndMB, _iIndex, &tbb))
  583. {
  584. dwState = tbb.fsState; // ToolBar_GetState returns -1 for some menus, need to use ToolBar_GetButton
  585. }
  586. int idHotTracked = ToolBar_GetHotItem(_pmtbItem->_hwndMB);
  587. DWORD dwAccState;
  588. if (dwState & TBSTATE_ENABLED)
  589. {
  590. dwAccState = STATE_SYSTEM_FOCUSABLE;
  591. }
  592. else
  593. {
  594. dwAccState = STATE_SYSTEM_UNAVAILABLE;
  595. }
  596. if (dwState & (TBSTATE_PRESSED | TBSTATE_ENABLED))
  597. {
  598. dwAccState |= STATE_SYSTEM_SELECTABLE | STATE_SYSTEM_FOCUSED;
  599. }
  600. if ((-1 != idHotTracked) && (idHotTracked == _iIndex))
  601. {
  602. dwAccState |= STATE_SYSTEM_HOTTRACKED;
  603. }
  604. if (_pmtbItem->v_GetFlags(_idCmd) & SMIF_SUBMENU)
  605. {
  606. dwAccState |= STATE_SYSTEM_HASPOPUP;
  607. }
  608. pvarState->vt = VT_I4;
  609. pvarState->lVal = dwAccState;
  610. return NOERROR;
  611. }
  612. break;
  613. }
  614. return DISP_E_MEMBERNOTFOUND;
  615. }
  616. /*----------------------------------------------------------
  617. Purpose: IAccessible::get_accHelp method
  618. */
  619. STDMETHODIMP CAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp)
  620. {
  621. switch (_fState)
  622. {
  623. case MB_STATE_TRACK:
  624. if (_pInnerAcc)
  625. return _pInnerAcc->get_accHelp(varChild, pszHelp);
  626. break;
  627. case MB_STATE_MENU:
  628. case MB_STATE_ITEM:
  629. // Not implemented
  630. break;
  631. }
  632. return DISP_E_MEMBERNOTFOUND;
  633. }
  634. /*----------------------------------------------------------
  635. Purpose: IAccessible::get_accHelpTopic method
  636. */
  637. STDMETHODIMP CAccessible::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild, long* pidTopic)
  638. {
  639. switch (_fState)
  640. {
  641. case MB_STATE_TRACK:
  642. if (_pInnerAcc)
  643. return _pInnerAcc->get_accHelpTopic(pszHelpFile, varChild, pidTopic);
  644. break;
  645. case MB_STATE_MENU:
  646. case MB_STATE_ITEM:
  647. // Not implemented
  648. break;
  649. }
  650. return DISP_E_MEMBERNOTFOUND;
  651. }
  652. #define CH_PREFIX TEXT('&')
  653. TCHAR GetAccelerator(LPCTSTR psz, BOOL bUseDefault)
  654. {
  655. TCHAR ch = (TCHAR)-1;
  656. LPCTSTR pszAccel = psz;
  657. // then prefixes are allowed.... see if it has one
  658. do
  659. {
  660. pszAccel = StrChr(pszAccel, CH_PREFIX);
  661. if (pszAccel)
  662. {
  663. pszAccel = CharNext(pszAccel);
  664. // handle having &&
  665. if (*pszAccel != CH_PREFIX)
  666. ch = *pszAccel;
  667. else
  668. pszAccel = CharNext(pszAccel);
  669. }
  670. } while (pszAccel && (ch == (TCHAR)-1));
  671. if ((ch == (TCHAR)-1) && bUseDefault)
  672. {
  673. // Since we're unicocde, we don't need to mess with MBCS
  674. ch = *psz;
  675. }
  676. return ch;
  677. }
  678. /*----------------------------------------------------------
  679. Purpose: IAccessible::get_accKeyboardShortcut method
  680. */
  681. STDMETHODIMP CAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszKeyboardShortcut)
  682. {
  683. CMenuToolbarBase* pmtb;
  684. int iIndex;
  685. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  686. *pszKeyboardShortcut = NULL;
  687. switch (_fState)
  688. {
  689. case MB_STATE_TRACK:
  690. if (_pInnerAcc)
  691. return _pInnerAcc->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
  692. break;
  693. case MB_STATE_ITEM:
  694. pmtb = _pmtbItem;
  695. pmtb->AddRef();
  696. iIndex = _iIndex;
  697. goto labelGetaccel;
  698. case MB_STATE_MENU:
  699. {
  700. if (varChild.lVal != CHILDID_SELF)
  701. {
  702. if (SUCCEEDED(_GetChildFromVariant(&varChild, &pmtb, &iIndex)))
  703. {
  704. labelGetaccel:
  705. TCHAR szAccel[100] = TEXT("");
  706. if (pmtb->_hwndMB)
  707. {
  708. TCHAR sz[MAX_PATH];
  709. int idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  710. if (S_FALSE == _psma->IsEmpty())
  711. {
  712. int cch = SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, NULL);
  713. // cch is strlen of the string, not including terminator
  714. if (cch != 0 && cch < ARRAYSIZE(sz))
  715. {
  716. if (SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, (LPARAM)sz) > 0)
  717. {
  718. BOOL fVertical, fOpen;
  719. _psma->GetState(&fVertical, &fOpen);
  720. if (!fVertical)
  721. {
  722. // minus 1 since we'll be adding a char.
  723. LoadString(HINST_THISDLL, IDS_ACC_ALT, szAccel, ARRAYSIZE(szAccel) - 1);
  724. }
  725. int cchLen = lstrlen(szAccel);
  726. szAccel[cchLen] = GetAccelerator(sz, TRUE);
  727. szAccel[cchLen + 1] = TEXT('\0');
  728. hr = S_OK;
  729. }
  730. }
  731. }
  732. }
  733. if (SUCCEEDED(hr))
  734. {
  735. *pszKeyboardShortcut = SysAllocStringT(szAccel);
  736. if (!*pszKeyboardShortcut)
  737. hr = E_OUTOFMEMORY;
  738. }
  739. pmtb->Release();
  740. }
  741. }
  742. }
  743. break;
  744. }
  745. return hr;
  746. }
  747. /*----------------------------------------------------------
  748. Purpose: IAccessible::get_accFocus method
  749. */
  750. STDMETHODIMP CAccessible::get_accFocus(VARIANT * pvarFocusChild)
  751. {
  752. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  753. switch (_fState)
  754. {
  755. case MB_STATE_TRACK:
  756. if (_pInnerAcc)
  757. return _pInnerAcc->get_accFocus(pvarFocusChild);
  758. break;
  759. case MB_STATE_MENU:
  760. {
  761. pvarFocusChild->vt = VT_I4;
  762. pvarFocusChild->lVal = CHILDID_SELF;
  763. CMenuToolbarBase* pmtbTracked;
  764. _psma->GetTracked(&pmtbTracked);
  765. if (pmtbTracked)
  766. {
  767. if (pmtbTracked->_hwndMB)
  768. {
  769. int iIndex = ToolBar_GetHotItem(pmtbTracked->_hwndMB);
  770. hr = _GetVariantFromChildIndex(pmtbTracked->_hwndMB,
  771. iIndex, pvarFocusChild);
  772. }
  773. pmtbTracked->Release();
  774. }
  775. }
  776. break;
  777. case MB_STATE_ITEM:
  778. // Not implemented;
  779. break;
  780. }
  781. return hr;
  782. }
  783. /*----------------------------------------------------------
  784. Purpose: IAccessible::get_accSelection method
  785. */
  786. STDMETHODIMP CAccessible::get_accSelection(VARIANT * pvarSelectedChildren)
  787. {
  788. switch (_fState)
  789. {
  790. case MB_STATE_TRACK:
  791. if (_pInnerAcc)
  792. return _pInnerAcc->get_accSelection(pvarSelectedChildren);
  793. break;
  794. case MB_STATE_MENU:
  795. return get_accFocus(pvarSelectedChildren);
  796. break;
  797. case MB_STATE_ITEM:
  798. // Not implemented;
  799. break;
  800. }
  801. return DISP_E_MEMBERNOTFOUND;
  802. }
  803. /*----------------------------------------------------------
  804. Purpose: IAccessible::get_accDefaultAction method
  805. */
  806. STDMETHODIMP CAccessible::get_accDefaultAction(VARIANT varChild, BSTR* pszDefaultAction)
  807. {
  808. TCHAR sz[MAX_PATH];
  809. switch (_fState)
  810. {
  811. case MB_STATE_TRACK:
  812. if (_pInnerAcc)
  813. return _pInnerAcc->get_accDefaultAction(varChild, pszDefaultAction);
  814. break;
  815. case MB_STATE_MENU:
  816. {
  817. LoadString(HINST_THISDLL, IDS_ACC_CLOSE, sz, ARRAYSIZE(sz));
  818. *pszDefaultAction = SysAllocStringT(sz);
  819. if (!*pszDefaultAction)
  820. return E_OUTOFMEMORY;
  821. return NOERROR;
  822. }
  823. case MB_STATE_ITEM:
  824. {
  825. if (S_OK == _psma->IsEmpty())
  826. {
  827. sz[0] = TEXT('\0');
  828. }
  829. else
  830. {
  831. int iId = (_pmtbItem->v_GetFlags(_idCmd) & SMIF_SUBMENU) ? IDS_ACC_OPEN: IDS_ACC_EXEC;
  832. LoadString(HINST_THISDLL, iId, sz, ARRAYSIZE(sz));
  833. }
  834. *pszDefaultAction = SysAllocStringT(sz);
  835. if (!*pszDefaultAction)
  836. return E_OUTOFMEMORY;
  837. return NOERROR;
  838. }
  839. }
  840. return DISP_E_MEMBERNOTFOUND;
  841. }
  842. /*----------------------------------------------------------
  843. Purpose: IAccessible::accSelect method
  844. */
  845. STDMETHODIMP CAccessible::accSelect(long flagsSelect, VARIANT varChild)
  846. {
  847. switch (_fState)
  848. {
  849. case MB_STATE_TRACK:
  850. if (_pInnerAcc)
  851. return _pInnerAcc->accSelect(flagsSelect, varChild);
  852. break;
  853. case MB_STATE_MENU:
  854. case MB_STATE_ITEM:
  855. break;
  856. }
  857. return DISP_E_MEMBERNOTFOUND;
  858. }
  859. /*----------------------------------------------------------
  860. Purpose: IAccessible::accLocation method
  861. */
  862. STDMETHODIMP CAccessible::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  863. {
  864. CMenuToolbarBase* pmtb;
  865. int iIndex;
  866. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  867. switch (_fState)
  868. {
  869. case MB_STATE_TRACK:
  870. if (_pInnerAcc)
  871. return _pInnerAcc->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
  872. break;
  873. case MB_STATE_ITEM:
  874. pmtb = _pmtbItem;
  875. pmtb->AddRef();
  876. iIndex = _iIndex;
  877. hr = NOERROR;
  878. goto labelGetRect;
  879. case MB_STATE_MENU:
  880. {
  881. RECT rc;
  882. if (varChild.vt == VT_I4)
  883. {
  884. if (varChild.lVal == CHILDID_SELF)
  885. {
  886. IUnknown* punk;
  887. hr = _psma->GetParentSite(IID_PPV_ARG(IUnknown, &punk));
  888. if (SUCCEEDED(hr))
  889. {
  890. IOleWindow* poct;
  891. hr = IUnknown_QueryService(punk, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &poct));
  892. if (SUCCEEDED(hr))
  893. {
  894. HWND hwnd;
  895. hr = poct->GetWindow(&hwnd);
  896. if (SUCCEEDED(hr))
  897. {
  898. // Return the window rect of the menubar.
  899. GetWindowRect(hwnd, &rc);
  900. }
  901. poct->Release();
  902. }
  903. punk->Release();
  904. }
  905. }
  906. else
  907. {
  908. hr = _GetChildFromVariant(&varChild, &pmtb, &iIndex);
  909. if (SUCCEEDED(hr))
  910. {
  911. labelGetRect:
  912. if (pmtb->_hwndMB)
  913. {
  914. int idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  915. if (!ToolBar_GetRect(pmtb->_hwndMB, idCmd, &rc)) //1 based index
  916. hr = E_INVALIDARG;
  917. MapWindowPoints(pmtb->_hwndMB, NULL, (LPPOINT)&rc, 2);
  918. }
  919. else
  920. {
  921. hr = E_FAIL;
  922. }
  923. pmtb->Release();
  924. }
  925. }
  926. if (SUCCEEDED(hr))
  927. {
  928. *pxLeft = rc.left;
  929. *pyTop = rc.top;
  930. *pcxWidth = rc.right - rc.left;
  931. *pcyHeight = rc.bottom - rc.top;
  932. }
  933. }
  934. }
  935. break;
  936. }
  937. return hr;
  938. }
  939. /*----------------------------------------------------------
  940. Purpose: IAccessible::accNavigate method
  941. */
  942. STDMETHODIMP CAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  943. {
  944. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  945. switch (_fState)
  946. {
  947. case MB_STATE_TRACK:
  948. if (_pInnerAcc)
  949. return _pInnerAcc->accNavigate(navDir, varStart, pvarEndUpAt);
  950. break;
  951. case MB_STATE_MENU:
  952. return _Navigate(navDir, varStart, pvarEndUpAt);
  953. break;
  954. case MB_STATE_ITEM:
  955. {
  956. VARIANT varChild;
  957. _GetVariantFromChildIndex(NULL, _iAccIndex, &varChild);
  958. return _Navigate(navDir, varChild, pvarEndUpAt);
  959. }
  960. }
  961. return hr;
  962. }
  963. /*----------------------------------------------------------
  964. Purpose: IAccessible::accHitTest method
  965. */
  966. STDMETHODIMP CAccessible::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  967. {
  968. POINT pt = {xLeft, yTop};
  969. switch (_fState)
  970. {
  971. case MB_STATE_TRACK:
  972. if (_pInnerAcc)
  973. return _pInnerAcc->accHitTest(xLeft, yTop, pvarChildAtPoint);
  974. break;
  975. case MB_STATE_MENU:
  976. {
  977. if (_psma)
  978. {
  979. int iIndex;
  980. HWND hwnd = WindowFromPoint(pt);
  981. if (hwnd == _pmtbTop->_hwndMB || hwnd == _pmtbBottom->_hwndMB)
  982. {
  983. ScreenToClient(hwnd, &pt);
  984. iIndex = ToolBar_HitTest(hwnd, &pt);
  985. if (iIndex >= 0)
  986. {
  987. pvarChildAtPoint->vt = VT_DISPATCH;
  988. // This call expects the index to be an "Accessible" index which is one based
  989. VARIANT varChild;
  990. _GetVariantFromChildIndex(hwnd, iIndex, &varChild);
  991. //Since this is just returining an index, we don't need to test success
  992. _GetChildFromVariant(&varChild, NULL, &iIndex);
  993. return _GetAccessibleItem(iIndex, &pvarChildAtPoint->pdispVal);
  994. }
  995. }
  996. // Hmm, must be self
  997. pvarChildAtPoint->vt = VT_I4;
  998. pvarChildAtPoint->lVal = CHILDID_SELF;
  999. return S_OK;
  1000. }
  1001. }
  1002. break;
  1003. case MB_STATE_ITEM:
  1004. {
  1005. RECT rc;
  1006. MapWindowPoints(NULL, _pmtbItem->_hwndMB, &pt, 1);
  1007. if (ToolBar_GetRect(_pmtbItem->_hwndMB, _idCmd, &rc) &&
  1008. PtInRect(&rc, pt))
  1009. {
  1010. pvarChildAtPoint->vt = VT_I4;
  1011. pvarChildAtPoint->lVal = CHILDID_SELF;
  1012. }
  1013. else
  1014. {
  1015. pvarChildAtPoint->vt = VT_EMPTY;
  1016. pvarChildAtPoint->lVal = (DWORD)(-1);
  1017. }
  1018. return NOERROR;
  1019. }
  1020. break;
  1021. }
  1022. return DISP_E_MEMBERNOTFOUND;
  1023. }
  1024. /*----------------------------------------------------------
  1025. Purpose: IAccessible::accDoDefaultAction method
  1026. */
  1027. STDMETHODIMP CAccessible::accDoDefaultAction(VARIANT varChild)
  1028. {
  1029. switch (_fState)
  1030. {
  1031. case MB_STATE_TRACK:
  1032. if (_pInnerAcc)
  1033. return _pInnerAcc->accDoDefaultAction(varChild);
  1034. break;
  1035. case MB_STATE_MENU:
  1036. if (_psma)
  1037. return _psma->DoDefaultAction(&varChild);
  1038. break;
  1039. case MB_STATE_ITEM:
  1040. if (SendMessage(_pmtbItem->_hwndMB, TB_SETHOTITEM2, _iIndex,
  1041. HICF_OTHER | HICF_RESELECT | HICF_TOGGLEDROPDOWN))
  1042. return NOERROR;
  1043. }
  1044. return DISP_E_MEMBERNOTFOUND;
  1045. }
  1046. /*----------------------------------------------------------
  1047. Purpose: IAccessible::put_accName method
  1048. */
  1049. STDMETHODIMP CAccessible::put_accName(VARIANT varChild, BSTR szName)
  1050. {
  1051. switch (_fState)
  1052. {
  1053. case MB_STATE_TRACK:
  1054. if (_pInnerAcc)
  1055. return _pInnerAcc->put_accName(varChild, szName);
  1056. break;
  1057. }
  1058. return DISP_E_MEMBERNOTFOUND;
  1059. }
  1060. /*----------------------------------------------------------
  1061. Purpose: IAccessible::put_accValue method
  1062. */
  1063. STDMETHODIMP CAccessible::put_accValue(VARIANT varChild, BSTR pszValue)
  1064. {
  1065. switch (_fState)
  1066. {
  1067. case MB_STATE_TRACK:
  1068. if (_pInnerAcc)
  1069. return _pInnerAcc->put_accValue(varChild, pszValue);
  1070. break;
  1071. }
  1072. return DISP_E_MEMBERNOTFOUND;
  1073. }
  1074. HRESULT CAccessible::_Navigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  1075. {
  1076. ASSERT(pvarEndUpAt);
  1077. int iTBIndex;
  1078. HRESULT hr = S_FALSE;
  1079. TBBUTTONINFO tbInfo;
  1080. tbInfo.cbSize = sizeof(TBBUTTONINFO);
  1081. pvarEndUpAt->vt = VT_DISPATCH;
  1082. pvarEndUpAt->pdispVal = NULL;
  1083. int iIndex = 0; // 1 based index
  1084. _GetChildFromVariant(&varStart, NULL, &iIndex);
  1085. BOOL fVertical;
  1086. BOOL fOpen;
  1087. _psma->GetState(&fVertical, &fOpen);
  1088. if (!fVertical)
  1089. {
  1090. static const long navMap[] =
  1091. {
  1092. NAVDIR_LEFT, // Map to Up
  1093. NAVDIR_RIGHT, // Map to Down
  1094. NAVDIR_UP, // Map to Left
  1095. NAVDIR_DOWN, // Map to Right
  1096. };
  1097. // uhhhh what?
  1098. if (IsInRange(navDir, NAVDIR_UP, NAVDIR_RIGHT))
  1099. navDir = navMap[navDir - NAVDIR_UP];
  1100. }
  1101. switch (navDir)
  1102. {
  1103. case NAVDIR_NEXT:
  1104. {
  1105. VARIANT varVert = {0};
  1106. // For the Vertical case, Next should return an error.
  1107. // Is this band vertical?
  1108. // Don't do this for anything but the menu case.
  1109. if (_fState == MB_STATE_MENU &&
  1110. SUCCEEDED(IUnknown_QueryServiceExec(_psma, SID_SMenuBandParent, &CGID_MenuBand,
  1111. MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1112. varVert.boolVal == VARIANT_TRUE)
  1113. {
  1114. ASSERT(VT_BOOL == varVert.vt);
  1115. // Yes. Then punt
  1116. hr = S_FALSE;
  1117. break;
  1118. }
  1119. // Fall Through
  1120. }
  1121. //Fall through
  1122. case NAVDIR_DOWN:
  1123. hr = NOERROR;
  1124. while (SUCCEEDED(hr))
  1125. {
  1126. iIndex++;
  1127. VARIANT varTemp;
  1128. hr = _GetVariantFromChildIndex(NULL, iIndex, &varTemp);
  1129. if (SUCCEEDED(hr))
  1130. {
  1131. CMenuToolbarBase *pmtb;
  1132. hr = _GetChildFromVariant(&varTemp, &pmtb, &iTBIndex);
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. if (pmtb->_hwndMB)
  1136. {
  1137. tbInfo.dwMask = TBIF_STATE | TBIF_STYLE;
  1138. int idCmd = GetButtonCmd(pmtb->_hwndMB, iTBIndex);
  1139. ToolBar_GetButtonInfo(pmtb->_hwndMB, idCmd, &tbInfo);
  1140. }
  1141. else
  1142. {
  1143. hr = E_FAIL;
  1144. }
  1145. pmtb->Release();
  1146. if (!(tbInfo.fsState & TBSTATE_HIDDEN) &&
  1147. !(tbInfo.fsStyle & TBSTYLE_SEP))
  1148. {
  1149. break;
  1150. }
  1151. }
  1152. }
  1153. }
  1154. break;
  1155. case NAVDIR_FIRSTCHILD:
  1156. if (_fState == MB_STATE_ITEM)
  1157. {
  1158. pvarEndUpAt->vt = VT_EMPTY;
  1159. pvarEndUpAt->pdispVal = NULL;
  1160. hr = S_FALSE;
  1161. break;
  1162. }
  1163. iIndex = 0;
  1164. hr = NOERROR;
  1165. break;
  1166. case NAVDIR_LASTCHILD:
  1167. if (_fState == MB_STATE_ITEM)
  1168. {
  1169. pvarEndUpAt->vt = VT_EMPTY;
  1170. pvarEndUpAt->pdispVal = NULL;
  1171. hr = S_FALSE;
  1172. break;
  1173. }
  1174. iIndex = -1;
  1175. hr = NOERROR;
  1176. break;
  1177. case NAVDIR_LEFT:
  1178. pvarEndUpAt->vt = VT_DISPATCH;
  1179. return get_accParent(&pvarEndUpAt->pdispVal);
  1180. break;
  1181. case NAVDIR_RIGHT:
  1182. {
  1183. CMenuToolbarBase* pmtb = (varStart.lVal & TOOLBAR_MASK)? _pmtbTop : _pmtbBottom;
  1184. if (pmtb->_hwndMB)
  1185. {
  1186. int idCmd = GetButtonCmd(pmtb->_hwndMB, (varStart.lVal & ~TOOLBAR_MASK) - 1);
  1187. if (pmtb->v_GetFlags(idCmd) & SMIF_SUBMENU)
  1188. {
  1189. IMenuPopup* pmp;
  1190. hr = _psma->GetSubMenu(&varStart, IID_PPV_ARG(IMenuPopup, &pmp));
  1191. if (SUCCEEDED(hr))
  1192. {
  1193. IAccessible* pacc;
  1194. hr = IUnknown_QueryService(pmp, SID_SMenuBandChild, IID_PPV_ARG(IAccessible, &pacc));
  1195. if (SUCCEEDED(hr))
  1196. {
  1197. hr = pacc->accNavigate(NAVDIR_FIRSTCHILD, varStart, pvarEndUpAt);
  1198. pacc->Release();
  1199. }
  1200. pmp->Release();
  1201. }
  1202. }
  1203. }
  1204. else
  1205. {
  1206. hr = E_FAIL;
  1207. }
  1208. return hr;
  1209. }
  1210. break;
  1211. case NAVDIR_PREVIOUS:
  1212. {
  1213. VARIANT varVert = {0};
  1214. // For the Vertical case, Pervious should return an error.
  1215. // Is this band vertical?
  1216. // Don't do this for anything but the menu case.
  1217. if (_fState == MB_STATE_MENU &&
  1218. SUCCEEDED(IUnknown_QueryServiceExec(_psma, SID_SMenuBandParent, &CGID_MenuBand,
  1219. MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1220. varVert.boolVal == VARIANT_TRUE)
  1221. {
  1222. ASSERT(VT_BOOL == varVert.vt);
  1223. // Yes. Then punt
  1224. hr = S_FALSE;
  1225. break;
  1226. }
  1227. // Fall Through
  1228. }
  1229. //Fall through
  1230. case NAVDIR_UP:
  1231. hr = NOERROR;
  1232. while (SUCCEEDED(hr))
  1233. {
  1234. iIndex--;
  1235. VARIANT varTemp;
  1236. hr = _GetVariantFromChildIndex(NULL, iIndex, &varTemp);
  1237. if (SUCCEEDED(hr))
  1238. {
  1239. CMenuToolbarBase *pmtb;
  1240. hr = _GetChildFromVariant(&varTemp, &pmtb, &iTBIndex);
  1241. if (SUCCEEDED(hr))
  1242. {
  1243. if (iTBIndex == 0)
  1244. {
  1245. hr = S_FALSE;
  1246. //Don't navigate to self, allow the top bar to get a whack.
  1247. IUnknown* punk;
  1248. if (SUCCEEDED(_psma->GetParentSite(IID_PPV_ARG(IUnknown, &punk))))
  1249. {
  1250. IOleCommandTarget* poct;
  1251. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SMenuBandParent,
  1252. IID_PPV_ARG(IOleCommandTarget, &poct))))
  1253. {
  1254. VARIANT varVert = {0};
  1255. if (SUCCEEDED(poct->Exec(&CGID_MenuBand, MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1256. varVert.boolVal == VARIANT_FALSE)
  1257. {
  1258. ASSERT(VT_BOOL == varVert.vt);
  1259. IAccessible* pacc;
  1260. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SMenuBandParent,
  1261. IID_PPV_ARG(IAccessible, &pacc))))
  1262. {
  1263. VARIANT varChild = {VT_I4, CHILDID_SELF};
  1264. hr = pacc->get_accFocus(&varChild);
  1265. if (SUCCEEDED(hr))
  1266. {
  1267. hr = pacc->get_accChild(varChild, &pvarEndUpAt->pdispVal);
  1268. }
  1269. VariantClear(&varChild);
  1270. pacc->Release();
  1271. }
  1272. }
  1273. poct->Release();
  1274. }
  1275. punk->Release();
  1276. }
  1277. } // iTBIndex == 0
  1278. tbInfo.dwMask = TBIF_STATE | TBIF_STYLE;
  1279. if (pmtb->_hwndMB)
  1280. {
  1281. int idCmd = GetButtonCmd(pmtb->_hwndMB, iTBIndex);
  1282. ToolBar_GetButtonInfo(pmtb->_hwndMB, idCmd, &tbInfo);
  1283. }
  1284. else
  1285. {
  1286. hr = E_FAIL;
  1287. }
  1288. pmtb->Release();
  1289. if (!(tbInfo.fsState & TBSTATE_HIDDEN) &&
  1290. !(tbInfo.fsStyle & TBSTYLE_SEP))
  1291. {
  1292. break;
  1293. }
  1294. }
  1295. }
  1296. }
  1297. break;
  1298. default:
  1299. hr = E_INVALIDARG;
  1300. }
  1301. if (SUCCEEDED(hr) && S_FALSE != hr)
  1302. hr = _GetAccessibleItem(iIndex, &pvarEndUpAt->pdispVal);
  1303. return hr;
  1304. }
  1305. HRESULT CAccessible::_GetVariantFromChildIndex(HWND hwnd, int iIndex, VARIANT* pvarChild)
  1306. {
  1307. // First bit: Top 1, bottom 0
  1308. // Rest is index into that toolbar.
  1309. pvarChild->vt = VT_I4;
  1310. pvarChild->lVal = iIndex + 1;
  1311. if (hwnd)
  1312. {
  1313. if (hwnd == _pmtbTop->_hwndMB)
  1314. {
  1315. pvarChild->lVal |= TOOLBAR_MASK;
  1316. }
  1317. }
  1318. else
  1319. {
  1320. // Caller wants us to figure out based on index from top.
  1321. int iTopCount = ToolBar_ButtonCount(_pmtbTop->_hwndMB);
  1322. int iBottomCount = ToolBar_ButtonCount(_pmtbBottom->_hwndMB);
  1323. int iTotalCount = (_pmtbTop != _pmtbBottom)? iTopCount + iBottomCount : iTopCount;
  1324. if (iIndex < iTopCount)
  1325. {
  1326. pvarChild->lVal |= TOOLBAR_MASK;
  1327. }
  1328. else
  1329. {
  1330. pvarChild->lVal -= iTopCount;
  1331. }
  1332. // This works because:
  1333. // If there are 2 toolbars, the bottom one is represented by top bit clear.
  1334. // If there is only one, then it doesn't matter if it's top or bottom.
  1335. // lVal is not zero based....
  1336. if (iIndex == -1)
  1337. pvarChild->lVal = iTotalCount;
  1338. if (iIndex >= iTotalCount)
  1339. return E_FAIL;
  1340. }
  1341. return NOERROR;
  1342. }
  1343. HRESULT CAccessible::_GetChildFromVariant(VARIANT* pvarChild, CMenuToolbarBase** ppmtb, int* piIndex)
  1344. {
  1345. ASSERT(_pmtbTop && _pmtbBottom);
  1346. ASSERT(piIndex);
  1347. if (ppmtb)
  1348. *ppmtb = NULL;
  1349. *piIndex = -1;
  1350. // Passing a NULL for an HWND returns the index from the beginning of the set.
  1351. int iAdd = 0;
  1352. if (pvarChild->vt != VT_I4)
  1353. return E_FAIL;
  1354. if (pvarChild->lVal & TOOLBAR_MASK)
  1355. {
  1356. if (ppmtb)
  1357. {
  1358. *ppmtb = _pmtbTop;
  1359. }
  1360. }
  1361. else
  1362. {
  1363. if (ppmtb)
  1364. {
  1365. *ppmtb = _pmtbBottom;
  1366. }
  1367. else
  1368. {
  1369. iAdd = ToolBar_ButtonCount(_pmtbTop->_hwndMB);
  1370. }
  1371. }
  1372. if (ppmtb && *ppmtb)
  1373. (*ppmtb)->AddRef();
  1374. *piIndex = (pvarChild->lVal & ~TOOLBAR_MASK) + iAdd - 1;
  1375. return (ppmtb && !*ppmtb) ? E_FAIL : S_OK;
  1376. }
  1377. HRESULT CAccessible::_GetAccessibleItem(int iIndex, IDispatch** ppdisp)
  1378. {
  1379. HRESULT hr = E_OUTOFMEMORY;
  1380. CAccessible* pacc = new CAccessible(_pmb, iIndex);
  1381. if (pacc)
  1382. {
  1383. if (SUCCEEDED(pacc->InitAcc()))
  1384. {
  1385. hr = pacc->QueryInterface(IID_PPV_ARG(IDispatch, ppdisp));
  1386. }
  1387. pacc->Release();
  1388. }
  1389. return hr;
  1390. }
  1391. // *** IEnumVARIANT methods ***
  1392. STDMETHODIMP CAccessible::Next(unsigned long celt,
  1393. VARIANT * rgvar,
  1394. unsigned long * pceltFetched)
  1395. {
  1396. // Picky customer complaint. Check for NULL...
  1397. if (pceltFetched)
  1398. *pceltFetched = 1;
  1399. return _GetVariantFromChildIndex(NULL, _iEnumIndex++, rgvar);
  1400. }
  1401. STDMETHODIMP CAccessible::Skip(unsigned long celt)
  1402. {
  1403. return E_NOTIMPL;
  1404. }
  1405. STDMETHODIMP CAccessible::Reset()
  1406. {
  1407. _iEnumIndex = 0;
  1408. return NOERROR;
  1409. }
  1410. STDMETHODIMP CAccessible::Clone(IEnumVARIANT ** ppenum)
  1411. {
  1412. return E_NOTIMPL;
  1413. }
  1414. // *** IOleWindow methods ***
  1415. STDMETHODIMP CAccessible::GetWindow(HWND * lphwnd)
  1416. {
  1417. *lphwnd = NULL;
  1418. switch (_fState)
  1419. {
  1420. case MB_STATE_TRACK:
  1421. *lphwnd = _hwndMenuWindow;
  1422. break;
  1423. case MB_STATE_ITEM:
  1424. *lphwnd = _pmtbItem->_hwndMB;
  1425. break;
  1426. case MB_STATE_MENU:
  1427. *lphwnd = _pmtbTop->_hwndMB;
  1428. break;
  1429. }
  1430. if (*lphwnd)
  1431. return NOERROR;
  1432. return E_FAIL;
  1433. }
  1434. STDMETHODIMP CAccessible::ContextSensitiveHelp(BOOL fEnterMode)
  1435. {
  1436. return E_NOTIMPL;
  1437. }