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.

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