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.

1606 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. /*----------------------------------------------------------
  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. switch (_fState)
  402. {
  403. case MB_STATE_TRACK:
  404. if (_pInnerAcc)
  405. return _pInnerAcc->get_accName(varChild, pszName);
  406. break;
  407. case MB_STATE_MENU:
  408. if (varChild.lVal == CHILDID_SELF)
  409. {
  410. if (_GetAccName(pszName) == S_FALSE)
  411. {
  412. TCHAR sz[100];
  413. MLLoadString(IDS_ACC_APP, sz, ARRAYSIZE(sz));
  414. *pszName = SysAllocStringT(sz);
  415. if (!*pszName)
  416. return E_OUTOFMEMORY;
  417. }
  418. return NOERROR;
  419. }
  420. else
  421. {
  422. int iIndex;
  423. if (FAILED(_GetChildFromVariant(&varChild, &pmtb, &iIndex)))
  424. return DISP_E_MEMBERNOTFOUND;
  425. idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  426. }
  427. // Fall Through
  428. case MB_STATE_ITEM:
  429. {
  430. TCHAR sz[MAX_PATH];
  431. int idString = 0;
  432. TBBUTTON tbb;
  433. if (ToolBar_GetButton(pmtb->_hwndMB, _iIndex, &tbb) &&
  434. tbb.fsStyle & BTNS_SEP)
  435. {
  436. idString = IDS_ACC_SEP;
  437. }
  438. else if (pmtb->GetChevronID() == _idCmd)
  439. {
  440. idString = IDS_ACC_CHEVRON;
  441. }
  442. if (idString != 0)
  443. {
  444. MLLoadString(idString, sz, ARRAYSIZE(sz));
  445. *pszName = SysAllocStringT(sz);
  446. }
  447. else if (SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, (LPARAM)sz) > 0)
  448. {
  449. SHStripMneumonic(sz);
  450. *pszName = SysAllocString(sz);
  451. }
  452. if (_fState == MB_STATE_MENU)
  453. pmtb->Release();
  454. if (!*pszName)
  455. return E_OUTOFMEMORY;
  456. return NOERROR;
  457. }
  458. break;
  459. }
  460. return DISP_E_MEMBERNOTFOUND;
  461. }
  462. /*----------------------------------------------------------
  463. Purpose: IAccessible::get_accValue method
  464. */
  465. STDMETHODIMP CAccessible::get_accValue(VARIANT varChild, BSTR* pszValue)
  466. {
  467. switch (_fState)
  468. {
  469. case MB_STATE_TRACK:
  470. if (_pInnerAcc)
  471. return _pInnerAcc->get_accValue(varChild, pszValue);
  472. break;
  473. case MB_STATE_MENU:
  474. case MB_STATE_ITEM:
  475. // This does not make sense for these.
  476. break;
  477. }
  478. return DISP_E_MEMBERNOTFOUND;
  479. }
  480. /*----------------------------------------------------------
  481. Purpose: IAccessible::get_accDescription method
  482. */
  483. STDMETHODIMP CAccessible::get_accDescription(VARIANT varChild, BSTR FAR* pszDescription)
  484. {
  485. switch (_fState)
  486. {
  487. case MB_STATE_TRACK:
  488. if (_pInnerAcc)
  489. return _pInnerAcc->get_accDescription(varChild, pszDescription);
  490. break;
  491. case MB_STATE_MENU:
  492. if (FAILED(_GetAccName(pszDescription)))
  493. {
  494. TCHAR sz[100];
  495. MLLoadString(IDS_ACC_APPMB, sz, ARRAYSIZE(sz));
  496. *pszDescription = SysAllocStringT(sz);
  497. if (!*pszDescription)
  498. return E_OUTOFMEMORY;
  499. }
  500. break;
  501. case MB_STATE_ITEM:
  502. return get_accName(varChild, pszDescription);
  503. break;
  504. }
  505. return DISP_E_MEMBERNOTFOUND;
  506. }
  507. /*----------------------------------------------------------
  508. Purpose: IAccessible::get_accRole method
  509. */
  510. STDMETHODIMP CAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  511. {
  512. pvarRole->vt = VT_I4;
  513. switch (_fState)
  514. {
  515. case MB_STATE_TRACK:
  516. if (_pInnerAcc)
  517. return _pInnerAcc->get_accRole(varChild, pvarRole);
  518. break;
  519. case MB_STATE_MENU:
  520. {
  521. BOOL fVertical;
  522. BOOL fOpen;
  523. _psma->GetState(&fVertical, &fOpen);
  524. pvarRole->lVal = ( fVertical )? ROLE_SYSTEM_MENUPOPUP : ROLE_SYSTEM_MENUBAR;
  525. return NOERROR;
  526. }
  527. case MB_STATE_ITEM:
  528. pvarRole->lVal = ROLE_SYSTEM_MENUITEM;
  529. return NOERROR;
  530. }
  531. return DISP_E_MEMBERNOTFOUND;
  532. }
  533. /*----------------------------------------------------------
  534. Purpose: IAccessible::get_accState method
  535. */
  536. STDMETHODIMP CAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
  537. {
  538. switch (_fState)
  539. {
  540. case MB_STATE_TRACK:
  541. if (_pInnerAcc)
  542. return _pInnerAcc->get_accState(varChild, pvarState);
  543. break;
  544. case MB_STATE_MENU:
  545. {
  546. // All menus can be selected, and given focus. Most will be visible.
  547. DWORD dwState = STATE_SYSTEM_FOCUSABLE;
  548. BOOL fOpen;
  549. BOOL fVertical;
  550. _psma->GetState(&fVertical, &fOpen);
  551. // Do we have a menu popped up?
  552. if (fOpen)
  553. {
  554. // Yes, then we have focus
  555. dwState |= STATE_SYSTEM_FOCUSED;
  556. }
  557. else if (fVertical)
  558. {
  559. // If we're a vertical menu without being popped up, then we're invisible.
  560. dwState |= STATE_SYSTEM_INVISIBLE;
  561. }
  562. pvarState->vt = VT_I4;
  563. pvarState->lVal = dwState;
  564. }
  565. return NOERROR;
  566. case MB_STATE_ITEM:
  567. {
  568. DWORD dwAccState = STATE_SYSTEM_FOCUSABLE;
  569. int idHotTracked = ToolBar_GetHotItem(_pmtbItem->_hwndMB);
  570. DWORD dwState = ToolBar_GetState(_pmtbItem->_hwndMB, _iIndex);
  571. if (dwState & TBSTATE_PRESSED)
  572. dwAccState |= STATE_SYSTEM_SELECTABLE | STATE_SYSTEM_FOCUSED;
  573. if (idHotTracked == _iIndex)
  574. dwAccState |= STATE_SYSTEM_HOTTRACKED;
  575. pvarState->vt = VT_I4;
  576. pvarState->lVal = dwAccState;
  577. return NOERROR;
  578. }
  579. break;
  580. }
  581. return DISP_E_MEMBERNOTFOUND;
  582. }
  583. /*----------------------------------------------------------
  584. Purpose: IAccessible::get_accHelp method
  585. */
  586. STDMETHODIMP CAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp)
  587. {
  588. switch (_fState)
  589. {
  590. case MB_STATE_TRACK:
  591. if (_pInnerAcc)
  592. return _pInnerAcc->get_accHelp(varChild, pszHelp);
  593. break;
  594. case MB_STATE_MENU:
  595. case MB_STATE_ITEM:
  596. // Not implemented
  597. break;
  598. }
  599. return DISP_E_MEMBERNOTFOUND;
  600. }
  601. /*----------------------------------------------------------
  602. Purpose: IAccessible::get_accHelpTopic method
  603. */
  604. STDMETHODIMP CAccessible::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild, long* pidTopic)
  605. {
  606. switch (_fState)
  607. {
  608. case MB_STATE_TRACK:
  609. if (_pInnerAcc)
  610. return _pInnerAcc->get_accHelpTopic(pszHelpFile, varChild, pidTopic);
  611. break;
  612. case MB_STATE_MENU:
  613. case MB_STATE_ITEM:
  614. // Not implemented
  615. break;
  616. }
  617. return DISP_E_MEMBERNOTFOUND;
  618. }
  619. #define CH_PREFIX TEXT('&')
  620. TCHAR GetAccelerator(LPCTSTR psz, BOOL bUseDefault)
  621. {
  622. TCHAR ch = (TCHAR)-1;
  623. LPCTSTR pszAccel = psz;
  624. // then prefixes are allowed.... see if it has one
  625. do
  626. {
  627. pszAccel = StrChr(pszAccel, CH_PREFIX);
  628. if (pszAccel)
  629. {
  630. pszAccel = CharNext(pszAccel);
  631. // handle having &&
  632. if (*pszAccel != CH_PREFIX)
  633. ch = *pszAccel;
  634. else
  635. pszAccel = CharNext(pszAccel);
  636. }
  637. } while (pszAccel && (ch == (TCHAR)-1));
  638. if ((ch == (TCHAR)-1) && bUseDefault)
  639. {
  640. // Since we're unicocde, we don't need to mess with MBCS
  641. ch = *psz;
  642. }
  643. return ch;
  644. }
  645. /*----------------------------------------------------------
  646. Purpose: IAccessible::get_accKeyboardShortcut method
  647. */
  648. STDMETHODIMP CAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszKeyboardShortcut)
  649. {
  650. CMenuToolbarBase* pmtb;
  651. int iIndex;
  652. HRESULT hres = DISP_E_MEMBERNOTFOUND;
  653. switch (_fState)
  654. {
  655. case MB_STATE_TRACK:
  656. if (_pInnerAcc)
  657. return _pInnerAcc->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
  658. break;
  659. case MB_STATE_ITEM:
  660. pmtb = _pmtbItem;
  661. pmtb->AddRef();
  662. iIndex = _iIndex;
  663. goto labelGetaccel;
  664. case MB_STATE_MENU:
  665. {
  666. if (varChild.lVal != CHILDID_SELF)
  667. {
  668. if (SUCCEEDED(_GetChildFromVariant(&varChild, &pmtb, &iIndex)))
  669. {
  670. labelGetaccel:
  671. TCHAR sz[MAX_PATH];
  672. TCHAR szAccel[100] = TEXT("");
  673. int idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  674. if (S_FALSE == _psma->IsEmpty())
  675. {
  676. if (SendMessage(pmtb->_hwndMB, TB_GETBUTTONTEXT, idCmd, (LPARAM)sz) > 0)
  677. {
  678. BOOL fVertical, fOpen;
  679. _psma->GetState(&fVertical, &fOpen);
  680. if (!fVertical)
  681. {
  682. MLLoadString(IDS_ACC_ALT, szAccel, ARRAYSIZE(szAccel));
  683. }
  684. szAccel[lstrlen(szAccel)] = GetAccelerator(sz, TRUE);
  685. szAccel[lstrlen(szAccel)] = TEXT('\0');
  686. hres = S_OK;
  687. }
  688. }
  689. *pszKeyboardShortcut = SysAllocStringT(szAccel);
  690. if (!*pszKeyboardShortcut)
  691. hres = E_OUTOFMEMORY;
  692. pmtb->Release();
  693. }
  694. }
  695. }
  696. break;
  697. }
  698. return hres;
  699. }
  700. /*----------------------------------------------------------
  701. Purpose: IAccessible::get_accFocus method
  702. */
  703. STDMETHODIMP CAccessible::get_accFocus(VARIANT FAR * pvarFocusChild)
  704. {
  705. HRESULT hres = DISP_E_MEMBERNOTFOUND;
  706. switch (_fState)
  707. {
  708. case MB_STATE_TRACK:
  709. if (_pInnerAcc)
  710. return _pInnerAcc->get_accFocus(pvarFocusChild);
  711. break;
  712. case MB_STATE_MENU:
  713. {
  714. pvarFocusChild->vt = VT_I4;
  715. pvarFocusChild->lVal = CHILDID_SELF;
  716. CMenuToolbarBase* pmtbTracked;
  717. _psma->GetTracked(&pmtbTracked);
  718. if (pmtbTracked)
  719. {
  720. int iIndex = ToolBar_GetHotItem(pmtbTracked->_hwndMB);
  721. hres = _GetVariantFromChildIndex(pmtbTracked->_hwndMB,
  722. iIndex, pvarFocusChild);
  723. pmtbTracked->Release();
  724. }
  725. }
  726. break;
  727. case MB_STATE_ITEM:
  728. // Not implemented;
  729. break;
  730. }
  731. return hres;
  732. }
  733. /*----------------------------------------------------------
  734. Purpose: IAccessible::get_accSelection method
  735. */
  736. STDMETHODIMP CAccessible::get_accSelection(VARIANT FAR * pvarSelectedChildren)
  737. {
  738. switch (_fState)
  739. {
  740. case MB_STATE_TRACK:
  741. if (_pInnerAcc)
  742. return _pInnerAcc->get_accSelection(pvarSelectedChildren);
  743. break;
  744. case MB_STATE_MENU:
  745. return get_accFocus(pvarSelectedChildren);
  746. break;
  747. case MB_STATE_ITEM:
  748. // Not implemented;
  749. break;
  750. }
  751. return DISP_E_MEMBERNOTFOUND;
  752. }
  753. /*----------------------------------------------------------
  754. Purpose: IAccessible::get_accDefaultAction method
  755. */
  756. STDMETHODIMP CAccessible::get_accDefaultAction(VARIANT varChild, BSTR* pszDefaultAction)
  757. {
  758. TCHAR sz[MAX_PATH];
  759. switch (_fState)
  760. {
  761. case MB_STATE_TRACK:
  762. if (_pInnerAcc)
  763. return _pInnerAcc->get_accDefaultAction(varChild, pszDefaultAction);
  764. break;
  765. case MB_STATE_MENU:
  766. {
  767. MLLoadString(IDS_ACC_CLOSE, sz, ARRAYSIZE(sz));
  768. *pszDefaultAction = SysAllocStringT(sz);
  769. if (!*pszDefaultAction)
  770. return E_OUTOFMEMORY;
  771. return NOERROR;
  772. }
  773. case MB_STATE_ITEM:
  774. {
  775. if (S_OK == _psma->IsEmpty())
  776. {
  777. sz[0] = TEXT('\0');
  778. }
  779. else
  780. {
  781. int iId = (_pmtbItem->v_GetFlags(_idCmd) & SMIF_SUBMENU)? IDS_ACC_OPEN: IDS_ACC_EXEC;
  782. MLLoadString(iId, sz, ARRAYSIZE(sz));
  783. }
  784. *pszDefaultAction = SysAllocStringT(sz);
  785. if (!*pszDefaultAction)
  786. return E_OUTOFMEMORY;
  787. return NOERROR;
  788. }
  789. }
  790. return DISP_E_MEMBERNOTFOUND;
  791. }
  792. /*----------------------------------------------------------
  793. Purpose: IAccessible::accSelect method
  794. */
  795. STDMETHODIMP CAccessible::accSelect(long flagsSelect, VARIANT varChild)
  796. {
  797. switch (_fState)
  798. {
  799. case MB_STATE_TRACK:
  800. if (_pInnerAcc)
  801. return _pInnerAcc->accSelect(flagsSelect, varChild);
  802. break;
  803. case MB_STATE_MENU:
  804. case MB_STATE_ITEM:
  805. break;
  806. }
  807. return DISP_E_MEMBERNOTFOUND;
  808. }
  809. /*----------------------------------------------------------
  810. Purpose: IAccessible::accLocation method
  811. */
  812. STDMETHODIMP CAccessible::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  813. {
  814. CMenuToolbarBase* pmtb;
  815. int iIndex;
  816. HRESULT hres = DISP_E_MEMBERNOTFOUND;
  817. switch (_fState)
  818. {
  819. case MB_STATE_TRACK:
  820. if (_pInnerAcc)
  821. return _pInnerAcc->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
  822. break;
  823. case MB_STATE_ITEM:
  824. pmtb = _pmtbItem;
  825. pmtb->AddRef();
  826. iIndex = _iIndex;
  827. hres = NOERROR;
  828. goto labelGetRect;
  829. case MB_STATE_MENU:
  830. {
  831. RECT rc;
  832. if (varChild.vt == VT_I4)
  833. {
  834. if (varChild.lVal == CHILDID_SELF)
  835. {
  836. IUnknown* punk;
  837. hres = _psma->GetParentSite(IID_IUnknown, (void**)&punk);
  838. if (SUCCEEDED(hres))
  839. {
  840. IOleWindow* poct;
  841. hres = IUnknown_QueryService(punk, SID_SMenuPopup,
  842. IID_IOleWindow, (void**)&poct);
  843. if (SUCCEEDED(hres))
  844. {
  845. HWND hwnd;
  846. hres = poct->GetWindow(&hwnd);
  847. if (SUCCEEDED(hres))
  848. {
  849. // Return the window rect of the menubar.
  850. GetWindowRect(hwnd, &rc);
  851. }
  852. poct->Release();
  853. }
  854. punk->Release();
  855. }
  856. }
  857. else
  858. {
  859. hres = _GetChildFromVariant(&varChild, &pmtb, &iIndex);
  860. if (SUCCEEDED(hres))
  861. {
  862. labelGetRect: int idCmd = GetButtonCmd(pmtb->_hwndMB, iIndex);
  863. if (!ToolBar_GetRect(pmtb->_hwndMB, idCmd, &rc)) //1 based index
  864. hres = E_INVALIDARG;
  865. MapWindowPoints(pmtb->_hwndMB, NULL, (LPPOINT)&rc, 2);
  866. pmtb->Release();
  867. }
  868. }
  869. if (SUCCEEDED(hres))
  870. {
  871. *pxLeft = rc.left;
  872. *pyTop = rc.top;
  873. *pcxWidth = rc.right - rc.left;
  874. *pcyHeight = rc.bottom - rc.top;
  875. }
  876. }
  877. }
  878. break;
  879. }
  880. return hres;
  881. }
  882. /*----------------------------------------------------------
  883. Purpose: IAccessible::accNavigate method
  884. */
  885. STDMETHODIMP CAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  886. {
  887. HRESULT hres = DISP_E_MEMBERNOTFOUND;
  888. switch (_fState)
  889. {
  890. case MB_STATE_TRACK:
  891. if (_pInnerAcc)
  892. return _pInnerAcc->accNavigate(navDir, varStart, pvarEndUpAt);
  893. break;
  894. case MB_STATE_MENU:
  895. return _Navigate(navDir, varStart, pvarEndUpAt);
  896. break;
  897. case MB_STATE_ITEM:
  898. {
  899. VARIANT varChild;
  900. _GetVariantFromChildIndex(NULL, _iAccIndex, &varChild);
  901. return _Navigate(navDir, varChild, pvarEndUpAt);
  902. }
  903. }
  904. return hres;
  905. }
  906. /*----------------------------------------------------------
  907. Purpose: IAccessible::accHitTest method
  908. */
  909. STDMETHODIMP CAccessible::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  910. {
  911. POINT pt = {xLeft, yTop};
  912. switch (_fState)
  913. {
  914. case MB_STATE_TRACK:
  915. if (_pInnerAcc)
  916. return _pInnerAcc->accHitTest(xLeft, yTop, pvarChildAtPoint);
  917. break;
  918. case MB_STATE_MENU:
  919. {
  920. if (_psma)
  921. {
  922. int iIndex;
  923. HWND hwnd = WindowFromPoint(pt);
  924. if (hwnd == _pmtbTop->_hwndMB || hwnd == _pmtbBottom->_hwndMB)
  925. {
  926. ScreenToClient(hwnd, &pt);
  927. iIndex = ToolBar_HitTest(hwnd, &pt);
  928. if (iIndex >= 0)
  929. {
  930. pvarChildAtPoint->vt = VT_DISPATCH;
  931. // This call expects the index to be an "Accessible" index which is one based
  932. VARIANT varChild;
  933. _GetVariantFromChildIndex(hwnd, iIndex, &varChild);
  934. //Since this is just returining an index, we don't need to test success
  935. _GetChildFromVariant(&varChild, NULL, &iIndex);
  936. return _GetAccessibleItem(iIndex, &pvarChildAtPoint->pdispVal);
  937. }
  938. }
  939. // Hmm, must be self
  940. pvarChildAtPoint->vt = VT_I4;
  941. pvarChildAtPoint->lVal = CHILDID_SELF;
  942. return S_OK;
  943. }
  944. }
  945. break;
  946. case MB_STATE_ITEM:
  947. {
  948. RECT rc;
  949. MapWindowPoints(NULL, _pmtbItem->_hwndMB, &pt, 1);
  950. if (ToolBar_GetRect(_pmtbItem->_hwndMB, _idCmd, &rc) &&
  951. PtInRect(&rc, pt))
  952. {
  953. pvarChildAtPoint->vt = VT_I4;
  954. pvarChildAtPoint->lVal = CHILDID_SELF;
  955. }
  956. else
  957. {
  958. pvarChildAtPoint->vt = VT_EMPTY;
  959. pvarChildAtPoint->lVal = (DWORD)(-1);
  960. }
  961. return NOERROR;
  962. }
  963. break;
  964. }
  965. return DISP_E_MEMBERNOTFOUND;
  966. }
  967. /*----------------------------------------------------------
  968. Purpose: IAccessible::accDoDefaultAction method
  969. */
  970. STDMETHODIMP CAccessible::accDoDefaultAction(VARIANT varChild)
  971. {
  972. switch (_fState)
  973. {
  974. case MB_STATE_TRACK:
  975. if (_pInnerAcc)
  976. return _pInnerAcc->accDoDefaultAction(varChild);
  977. break;
  978. case MB_STATE_MENU:
  979. if (_psma)
  980. return _psma->DoDefaultAction(&varChild);
  981. break;
  982. case MB_STATE_ITEM:
  983. if (SendMessage(_pmtbItem->_hwndMB, TB_SETHOTITEM2, _iIndex,
  984. HICF_OTHER | HICF_RESELECT | HICF_TOGGLEDROPDOWN))
  985. return NOERROR;
  986. }
  987. return DISP_E_MEMBERNOTFOUND;
  988. }
  989. /*----------------------------------------------------------
  990. Purpose: IAccessible::put_accName method
  991. */
  992. STDMETHODIMP CAccessible::put_accName(VARIANT varChild, BSTR szName)
  993. {
  994. switch (_fState)
  995. {
  996. case MB_STATE_TRACK:
  997. if (_pInnerAcc)
  998. return _pInnerAcc->put_accName(varChild, szName);
  999. break;
  1000. }
  1001. return DISP_E_MEMBERNOTFOUND;
  1002. }
  1003. /*----------------------------------------------------------
  1004. Purpose: IAccessible::put_accValue method
  1005. */
  1006. STDMETHODIMP CAccessible::put_accValue(VARIANT varChild, BSTR pszValue)
  1007. {
  1008. switch (_fState)
  1009. {
  1010. case MB_STATE_TRACK:
  1011. if (_pInnerAcc)
  1012. return _pInnerAcc->put_accValue(varChild, pszValue);
  1013. break;
  1014. }
  1015. return DISP_E_MEMBERNOTFOUND;
  1016. }
  1017. HRESULT CAccessible::_Navigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  1018. {
  1019. ASSERT(pvarEndUpAt);
  1020. int iIndex = 0; // 1 based index
  1021. int iTBIndex;
  1022. HRESULT hres = S_FALSE;
  1023. TBBUTTONINFO tbInfo;
  1024. int idCmd;
  1025. VARIANT varTemp;
  1026. CMenuToolbarBase* pmtb;
  1027. BOOL fVertical;
  1028. BOOL fOpen;
  1029. tbInfo.cbSize = sizeof(TBBUTTONINFO);
  1030. pvarEndUpAt->vt = VT_DISPATCH;
  1031. pvarEndUpAt->pdispVal = NULL;
  1032. _GetChildFromVariant(&varStart, NULL, &iIndex);
  1033. _psma->GetState(&fVertical, &fOpen);
  1034. if (!fVertical)
  1035. {
  1036. static const long navMap[] =
  1037. {
  1038. NAVDIR_LEFT, // Map to Up
  1039. NAVDIR_RIGHT, // Map to Down
  1040. NAVDIR_UP, // Map to Left
  1041. NAVDIR_DOWN, // Map to Right
  1042. };
  1043. if (IsInRange(navDir, NAVDIR_UP, NAVDIR_RIGHT))
  1044. navDir = navMap[navDir - NAVDIR_UP];
  1045. }
  1046. switch (navDir)
  1047. {
  1048. case NAVDIR_NEXT:
  1049. {
  1050. VARIANT varVert;
  1051. varVert.vt = VT_BOOL;
  1052. // For the Vertical case, Next should return an error.
  1053. // Is this band vertical?
  1054. // Don't do this for anything but the menu case.
  1055. if (_fState == MB_STATE_MENU &&
  1056. SUCCEEDED(IUnknown_QueryServiceExec(_psma, SID_SMenuBandParent, &CGID_MenuBand,
  1057. MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1058. varVert.boolVal == VARIANT_TRUE)
  1059. {
  1060. // Yes. Then punt
  1061. hres = S_FALSE;
  1062. break;
  1063. }
  1064. // Fall Through
  1065. }
  1066. //Fall through
  1067. case NAVDIR_DOWN:
  1068. hres = NOERROR;
  1069. while (SUCCEEDED(hres))
  1070. {
  1071. iIndex++;
  1072. hres = _GetVariantFromChildIndex(NULL, iIndex, &varTemp);
  1073. if (SUCCEEDED(hres))
  1074. {
  1075. hres = _GetChildFromVariant(&varTemp, &pmtb, &iTBIndex);
  1076. if (SUCCEEDED(hres))
  1077. {
  1078. tbInfo.dwMask = TBIF_STATE | TBIF_STYLE;
  1079. idCmd = GetButtonCmd(pmtb->_hwndMB, iTBIndex);
  1080. ToolBar_GetButtonInfo(pmtb->_hwndMB, idCmd, &tbInfo);
  1081. pmtb->Release();
  1082. if (!(tbInfo.fsState & TBSTATE_HIDDEN) &&
  1083. !(tbInfo.fsStyle & TBSTYLE_SEP))
  1084. {
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. break;
  1091. case NAVDIR_FIRSTCHILD:
  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 = 0;
  1100. hres = NOERROR;
  1101. break;
  1102. case NAVDIR_LASTCHILD:
  1103. if (_fState == MB_STATE_ITEM)
  1104. {
  1105. pvarEndUpAt->vt = VT_EMPTY;
  1106. pvarEndUpAt->pdispVal = NULL;
  1107. hres = S_FALSE;
  1108. break;
  1109. }
  1110. iIndex = -1;
  1111. hres = NOERROR;
  1112. break;
  1113. case NAVDIR_LEFT:
  1114. pvarEndUpAt->vt = VT_DISPATCH;
  1115. return get_accParent(&pvarEndUpAt->pdispVal);
  1116. break;
  1117. case NAVDIR_RIGHT:
  1118. {
  1119. CMenuToolbarBase* pmtb = (varStart.lVal & TOOLBAR_MASK)? _pmtbTop : _pmtbBottom;
  1120. int idCmd = GetButtonCmd(pmtb->_hwndMB, (varStart.lVal & ~TOOLBAR_MASK) - 1);
  1121. if (pmtb->v_GetFlags(idCmd) & SMIF_SUBMENU)
  1122. {
  1123. IMenuPopup* pmp;
  1124. hres = _psma->GetSubMenu(&varStart, IID_IMenuPopup, (void**)&pmp);
  1125. if (SUCCEEDED(hres))
  1126. {
  1127. IAccessible* pacc;
  1128. hres = IUnknown_QueryService(pmp, SID_SMenuBandChild, IID_IAccessible, (void**)&pacc);
  1129. if (SUCCEEDED(hres))
  1130. {
  1131. hres = pacc->accNavigate(NAVDIR_FIRSTCHILD, varStart, pvarEndUpAt);
  1132. pacc->Release();
  1133. }
  1134. pmp->Release();
  1135. }
  1136. }
  1137. return hres;
  1138. }
  1139. break;
  1140. case NAVDIR_PREVIOUS:
  1141. {
  1142. VARIANT varVert;
  1143. varVert.vt = VT_BOOL;
  1144. // For the Vertical case, Pervious should return an error.
  1145. // Is this band vertical?
  1146. // Don't do this for anything but the menu case.
  1147. if (_fState == MB_STATE_MENU &&
  1148. SUCCEEDED(IUnknown_QueryServiceExec(_psma, SID_SMenuBandParent, &CGID_MenuBand,
  1149. MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1150. varVert.boolVal == VARIANT_TRUE)
  1151. {
  1152. // Yes. Then punt
  1153. hres = S_FALSE;
  1154. break;
  1155. }
  1156. // Fall Through
  1157. }
  1158. //Fall through
  1159. case NAVDIR_UP:
  1160. hres = NOERROR;
  1161. while (SUCCEEDED(hres))
  1162. {
  1163. iIndex--;
  1164. hres = _GetVariantFromChildIndex(NULL, iIndex, &varTemp);
  1165. if (SUCCEEDED(hres))
  1166. {
  1167. hres = _GetChildFromVariant(&varTemp, &pmtb, &iTBIndex);
  1168. if (SUCCEEDED(hres))
  1169. {
  1170. if (iTBIndex == 0)
  1171. {
  1172. hres = S_FALSE;
  1173. //Don't navigate to self, allow the top bar to get a whack.
  1174. IUnknown* punk;
  1175. if (SUCCEEDED(_psma->GetParentSite(IID_IOleCommandTarget, (void**)&punk)))
  1176. {
  1177. IOleCommandTarget* poct;
  1178. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SMenuBandParent,
  1179. IID_IOleCommandTarget, (void**)&poct)))
  1180. {
  1181. VARIANT varVert;
  1182. varVert.vt = VT_BOOL;
  1183. if (SUCCEEDED(poct->Exec(&CGID_MenuBand, MBANDCID_ISVERTICAL, 0, NULL, &varVert)) &&
  1184. varVert.boolVal == VARIANT_FALSE)
  1185. {
  1186. IAccessible* pacc;
  1187. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SMenuBandParent,
  1188. IID_IAccessible, (void**)&pacc)))
  1189. {
  1190. VARIANT varChild = {VT_I4, CHILDID_SELF};
  1191. hres = pacc->get_accFocus(&varChild);
  1192. if (SUCCEEDED(hres))
  1193. {
  1194. hres = pacc->get_accChild(varChild, &pvarEndUpAt->pdispVal);
  1195. }
  1196. VariantClearLazy(&varChild);
  1197. pacc->Release();
  1198. }
  1199. }
  1200. poct->Release();
  1201. }
  1202. punk->Release();
  1203. }
  1204. } // iTBIndex == 0
  1205. tbInfo.dwMask = TBIF_STATE | TBIF_STYLE;
  1206. idCmd = GetButtonCmd(pmtb->_hwndMB, iTBIndex);
  1207. ToolBar_GetButtonInfo(pmtb->_hwndMB, idCmd, &tbInfo);
  1208. pmtb->Release();
  1209. if (!(tbInfo.fsState & TBSTATE_HIDDEN) &&
  1210. !(tbInfo.fsStyle & TBSTYLE_SEP))
  1211. {
  1212. break;
  1213. }
  1214. }
  1215. }
  1216. }
  1217. break;
  1218. default:
  1219. hres = E_INVALIDARG;
  1220. }
  1221. if (SUCCEEDED(hres) && S_FALSE != hres)
  1222. hres = _GetAccessibleItem(iIndex, &pvarEndUpAt->pdispVal);
  1223. return hres;
  1224. }
  1225. HRESULT CAccessible::_GetVariantFromChildIndex(HWND hwnd, int iIndex, VARIANT* pvarChild)
  1226. {
  1227. // First bit: Top 1, bottom 0
  1228. // Rest is index into that toolbar.
  1229. pvarChild->vt = VT_I4;
  1230. pvarChild->lVal = iIndex + 1;
  1231. if (hwnd)
  1232. {
  1233. if (hwnd == _pmtbTop->_hwndMB)
  1234. {
  1235. pvarChild->lVal |= TOOLBAR_MASK;
  1236. }
  1237. }
  1238. else
  1239. {
  1240. // Caller wants us to figure out based on index from top.
  1241. int iTopCount = ToolBar_ButtonCount(_pmtbTop->_hwndMB);
  1242. int iBottomCount = ToolBar_ButtonCount(_pmtbBottom->_hwndMB);
  1243. int iTotalCount = (_pmtbTop != _pmtbBottom)? iTopCount + iBottomCount : iTopCount;
  1244. if (iIndex < iTopCount)
  1245. {
  1246. pvarChild->lVal |= TOOLBAR_MASK;
  1247. }
  1248. else
  1249. {
  1250. pvarChild->lVal -= iTopCount;
  1251. }
  1252. // This works because:
  1253. // If there are 2 toolbars, the bottom one is represented by top bit clear.
  1254. // If there is only one, then it doesn't matter if it's top or bottom.
  1255. // lVal is not zero based....
  1256. if (iIndex == -1)
  1257. pvarChild->lVal = iTotalCount;
  1258. if (iIndex >= iTotalCount)
  1259. return E_FAIL;
  1260. }
  1261. return NOERROR;
  1262. }
  1263. HRESULT CAccessible::_GetChildFromVariant(VARIANT* pvarChild, CMenuToolbarBase** ppmtb, int* piIndex)
  1264. {
  1265. ASSERT(_pmtbTop && _pmtbBottom);
  1266. ASSERT(piIndex);
  1267. if (ppmtb)
  1268. *ppmtb = NULL;
  1269. *piIndex = -1;
  1270. // Passing a NULL for an HWND returns the index from the beginning of the set.
  1271. int iAdd = 0;
  1272. if (pvarChild->vt != VT_I4)
  1273. return E_FAIL;
  1274. if (pvarChild->lVal & TOOLBAR_MASK)
  1275. {
  1276. if (ppmtb)
  1277. {
  1278. *ppmtb = _pmtbTop;
  1279. }
  1280. }
  1281. else
  1282. {
  1283. if (ppmtb)
  1284. {
  1285. *ppmtb = _pmtbBottom;
  1286. }
  1287. else
  1288. {
  1289. iAdd = ToolBar_ButtonCount(_pmtbTop->_hwndMB);
  1290. }
  1291. }
  1292. if (ppmtb && *ppmtb)
  1293. (*ppmtb)->AddRef();
  1294. *piIndex = (pvarChild->lVal & ~TOOLBAR_MASK) + iAdd - 1;
  1295. return (ppmtb && !*ppmtb) ? E_FAIL : S_OK;
  1296. }
  1297. HRESULT CAccessible::_GetAccessibleItem(int iIndex, IDispatch** ppdisp)
  1298. {
  1299. HRESULT hres = E_OUTOFMEMORY;
  1300. CAccessible* pacc = new CAccessible(_pmb, iIndex);
  1301. if (pacc)
  1302. {
  1303. hres = pacc->InitAcc();
  1304. if (SUCCEEDED(hres))
  1305. {
  1306. hres = pacc->QueryInterface(IID_IDispatch, (void**) ppdisp);
  1307. }
  1308. pacc->Release();
  1309. }
  1310. return hres;
  1311. }
  1312. // *** IEnumVARIANT methods ***
  1313. STDMETHODIMP CAccessible::Next(unsigned long celt,
  1314. VARIANT FAR* rgvar,
  1315. unsigned long FAR* pceltFetched)
  1316. {
  1317. // Picky customer complaint. Check for NULL...
  1318. if (pceltFetched)
  1319. *pceltFetched = 1;
  1320. return _GetVariantFromChildIndex(NULL, _iEnumIndex++, rgvar);
  1321. }
  1322. STDMETHODIMP CAccessible::Skip(unsigned long celt)
  1323. {
  1324. return E_NOTIMPL;
  1325. }
  1326. STDMETHODIMP CAccessible::Reset()
  1327. {
  1328. _iEnumIndex = 0;
  1329. return NOERROR;
  1330. }
  1331. STDMETHODIMP CAccessible::Clone(IEnumVARIANT FAR* FAR* ppenum)
  1332. {
  1333. return E_NOTIMPL;
  1334. }
  1335. // *** IOleWindow methods ***
  1336. STDMETHODIMP CAccessible::GetWindow(HWND * lphwnd)
  1337. {
  1338. *lphwnd = NULL;
  1339. switch (_fState)
  1340. {
  1341. case MB_STATE_TRACK:
  1342. *lphwnd = _hwndMenuWindow;
  1343. break;
  1344. case MB_STATE_ITEM:
  1345. *lphwnd = _pmtbItem->_hwndMB;
  1346. break;
  1347. case MB_STATE_MENU:
  1348. *lphwnd = _pmtbTop->_hwndMB;
  1349. break;
  1350. }
  1351. if (*lphwnd)
  1352. return NOERROR;
  1353. return E_FAIL;
  1354. }
  1355. STDMETHODIMP CAccessible::ContextSensitiveHelp(BOOL fEnterMode)
  1356. {
  1357. return E_NOTIMPL;
  1358. }