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.

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