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.

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