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.

1590 lines
43 KiB

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