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.

2395 lines
66 KiB

  1. /*
  2. * IACCESS.CPP
  3. *
  4. * Purpose:
  5. * Implemenation of IAccessibility for listbox and combobox
  6. *
  7. * Original Author:
  8. * Jerry Kim
  9. *
  10. * History: <nl>
  11. * 01/04/99 - v-jerrki Created
  12. *
  13. * Set tabs every four (4) columns
  14. *
  15. * Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
  16. */
  17. #include "_common.h"
  18. #include "_host.h"
  19. #include "_cbhost.h"
  20. #ifndef NOACCESSIBILITY
  21. extern LRESULT CALLBACK RichListBoxWndProc(HWND, UINT, WPARAM, LPARAM);
  22. #define InitPv(pv) *pv = NULL
  23. #define InitPlong(plong) *plong = 0
  24. #define InitPvar(pvar) pvar->vt = VT_EMPTY
  25. #define ValidateFlags(flags, valid) (!((flags) & ~(valid)))
  26. #define InitAccLocation(px, py, pcx, pcy) {InitPlong(px); InitPlong(py); InitPlong(pcx); InitPlong(pcy);}
  27. #ifdef _WIN64
  28. #define HwndFromHWNDID(lId) (HWND)((DWORD_PTR)(lId) & ~0x80000000)
  29. #else
  30. #define HwndFromHWNDID(lId) (HWND)((lId) & ~0x80000000)
  31. #endif // _WIN64
  32. // this is for ClickOnTheRect
  33. typedef struct tagMOUSEINFO
  34. {
  35. int MouseThresh1;
  36. int MouseThresh2;
  37. int MouseSpeed;
  38. }
  39. MOUSEINFO, FAR* LPMOUSEINFO;
  40. #define IsHWNDID(lId) ((lId) & 0x80000000)
  41. //////////////////////// Accessibility Utility Functions ///////////////////////////
  42. namespace MSAA
  43. {
  44. // --------------------------------------------------------------------------
  45. //
  46. // InitTypeInfo()
  47. //
  48. // This initializes our type info when we need it for IDispatch junk.
  49. //
  50. // --------------------------------------------------------------------------
  51. HRESULT InitTypeInfo(ITypeInfo** ppiTypeInfo)
  52. {
  53. Assert(ppiTypeInfo);
  54. if (*ppiTypeInfo)
  55. return S_OK;
  56. // Try getting the typelib from the registry
  57. ITypeLib *piTypeLib;
  58. HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, 0, &piTypeLib);
  59. if (FAILED(hr))
  60. hr = LoadTypeLib(OLESTR("OLEACC.DLL"), &piTypeLib);
  61. if (SUCCEEDED(hr))
  62. {
  63. hr = piTypeLib->GetTypeInfoOfGuid(IID_IAccessible, ppiTypeInfo);
  64. piTypeLib->Release();
  65. if (!SUCCEEDED(hr))
  66. *ppiTypeInfo = NULL;
  67. }
  68. return(hr);
  69. }
  70. // --------------------------------------------------------------------------
  71. //
  72. // ValidateChild()
  73. //
  74. // --------------------------------------------------------------------------
  75. BOOL ValidateChild(VARIANT *pvar, int ctChild)
  76. {
  77. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "ValidateChild");
  78. // Missing parameter, a la VBA
  79. TryAgain:
  80. switch (pvar->vt)
  81. {
  82. case VT_VARIANT | VT_BYREF:
  83. W32->VariantCopy(pvar, pvar->pvarVal);
  84. goto TryAgain;
  85. case VT_ERROR:
  86. if (pvar->scode != DISP_E_PARAMNOTFOUND)
  87. return(FALSE);
  88. // FALL THRU
  89. case VT_EMPTY:
  90. pvar->vt = VT_I4;
  91. pvar->lVal = 0;
  92. break;
  93. case VT_I4:
  94. if ((pvar->lVal < 0) || (pvar->lVal > ctChild))
  95. return(FALSE);
  96. break;
  97. default:
  98. return(FALSE);
  99. }
  100. return(TRUE);
  101. }
  102. // --------------------------------------------------------------------------
  103. //
  104. // ValidateSelFlags()
  105. //
  106. // Validates selection flags.
  107. // this makes sure the only bits set are in the valid range and that you don't
  108. // have any invalid combinations.
  109. // Invalid combinations are
  110. // ADDSELECTION and REMOVESELECTION
  111. // ADDSELECTION and TAKESELECTION
  112. // REMOVESELECTION and TAKESELECTION
  113. // EXTENDSELECTION and TAKESELECTION
  114. //
  115. // --------------------------------------------------------------------------
  116. BOOL ValidateSelFlags(long flags)
  117. {
  118. if (!ValidateFlags((flags), SELFLAG_VALID))
  119. return (FALSE);
  120. if ((flags & SELFLAG_ADDSELECTION) &&
  121. (flags & SELFLAG_REMOVESELECTION))
  122. return FALSE;
  123. if ((flags & SELFLAG_ADDSELECTION) &&
  124. (flags & SELFLAG_TAKESELECTION))
  125. return FALSE;
  126. if ((flags & SELFLAG_REMOVESELECTION) &&
  127. (flags & SELFLAG_TAKESELECTION))
  128. return FALSE;
  129. if ((flags & SELFLAG_EXTENDSELECTION) &&
  130. (flags & SELFLAG_TAKESELECTION))
  131. return FALSE;
  132. return TRUE;
  133. }
  134. // --------------------------------------------------------------------------
  135. //
  136. // GetStringResource(UINT id, WCHAR* psz, int nSize)
  137. //
  138. // Gets the string resource for a given id and puts it in the passed buffer
  139. //
  140. // --------------------------------------------------------------------------
  141. HRESULT GetStringResource(UINT id, BSTR* pbstr)
  142. {
  143. WCHAR sz[MAX_PATH] = L"\0";
  144. if (!pbstr)
  145. return S_FALSE;
  146. /*
  147. // UNDONE:
  148. // Need a workaround for this localization issue
  149. if (Win9x())
  150. {
  151. if (!LoadStringA(hinstResDll, id, sz, MAX_PATH))
  152. return(E_OUTOFMEMORY);
  153. // On Win9x we get ansi so convert it
  154. int cchUText = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)sz, -1, NULL, 0) + 1;
  155. *pbstr = SysAllocStringLen(NULL, cchUText);
  156. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)psz, -1, *pbstr, cchUText);
  157. }
  158. else
  159. {
  160. if (!LoadStringW(hinstResDll, id, sz, MAX_PATH))
  161. return(E_OUTOFMEMORY);
  162. *pbstr = SysAllocString(sz);
  163. }
  164. */
  165. #define STR_DOUBLE_CLICK 1
  166. #define STR_DROPDOWN_HIDE 2
  167. #define STR_DROPDOWN_SHOW 3
  168. #define STR_ALT 4
  169. #define STR_COMBOBOX_LIST_SHORTCUT 5
  170. switch (id)
  171. {
  172. case STR_DOUBLE_CLICK:
  173. //"Double Click"
  174. wcscpy(sz, L"Double Click");
  175. break;
  176. case STR_DROPDOWN_HIDE:
  177. //"Hide"
  178. wcscpy(sz, L"Hide");
  179. break;
  180. case STR_DROPDOWN_SHOW:
  181. //"Show"
  182. wcscpy(sz, L"Show");
  183. break;
  184. case STR_ALT:
  185. //"Alt+"
  186. wcscpy(sz, L"Alt+");
  187. break;
  188. case STR_COMBOBOX_LIST_SHORTCUT:
  189. //"Alt+Down Arrow"
  190. wcscpy(sz, L"Alt+Down Arrow");
  191. break;
  192. default:
  193. AssertSz(FALSE, "id not found!!");
  194. }
  195. *pbstr = SysAllocString(sz);
  196. if (!*pbstr)
  197. return(E_OUTOFMEMORY);
  198. return(S_OK);
  199. }
  200. // --------------------------------------------------------------------------
  201. //
  202. // HWND GetAncestor(HWND hwnd, UINT gaFlags)
  203. //
  204. // This gets the ancestor window where
  205. // GA_PARENT gets the "real" parent window
  206. // GA_ROOT gets the "real" top level parent window (not inc. owner)r
  207. //
  208. // * The _real_ parent. This does NOT include the owner, unlike
  209. // GetParent(). Stops at a top level window unless we start with
  210. // the desktop. In which case, we return the desktop.
  211. // * The _real_ root, caused by walking up the chain getting the
  212. // ancestor.
  213. //
  214. // NOTE:
  215. // User32.exe provides a undocumented function similar to this but
  216. // it doesn't exist in NT4. Also, GA_ROOT works differently on Win98 so
  217. // I copied this over from msaa
  218. // --------------------------------------------------------------------------
  219. HWND GetAncestor(HWND hwnd, UINT gaFlags)
  220. {
  221. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetAncestor");
  222. HWND hwndDesktop = GetDesktopWindow();
  223. if (hwnd == hwndDesktop || !::IsWindow(hwnd))
  224. return(NULL);
  225. DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE);
  226. HWND hwndParent;
  227. switch (gaFlags)
  228. {
  229. case GA_PARENT:
  230. if (dwStyle & WS_CHILD)
  231. hwndParent = GetParent(hwnd);
  232. else
  233. hwndParent = GetWindow(hwnd, GW_OWNER);
  234. hwnd = hwndParent;
  235. break;
  236. case GA_ROOT:
  237. if (dwStyle & WS_CHILD)
  238. hwndParent = GetParent(hwnd);
  239. else
  240. hwndParent = GetWindow(hwnd, GW_OWNER);
  241. while (hwndParent != hwndDesktop && hwndParent != NULL)
  242. {
  243. hwnd = hwndParent;
  244. dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  245. if (dwStyle & WS_CHILD)
  246. hwndParent = GetParent(hwnd);
  247. else
  248. hwndParent = GetWindow(hwnd, GW_OWNER);
  249. }
  250. break;
  251. default:
  252. AssertSz(FALSE, "Invalid flag");
  253. }
  254. return(hwnd);
  255. }
  256. // --------------------------------------------------------------------------
  257. //
  258. // GetTextString(HWND hwnd, BSTR* bstr)
  259. //
  260. // Parameters: hwnd of the window to get the text from
  261. //
  262. // --------------------------------------------------------------------------
  263. HRESULT GetTextString(HWND hwnd, BSTR* pbstr)
  264. {
  265. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetTextString");
  266. WCHAR sz[MAX_PATH + 1];
  267. WCHAR *psz = sz;
  268. int cchText = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
  269. // allocate memory from heap if stack buffer is insufficient
  270. if (cchText >= MAX_PATH)
  271. psz = new WCHAR[cchText + 1];
  272. if (!psz)
  273. return E_OUTOFMEMORY;
  274. // retrieve text
  275. HRESULT hres = S_OK;
  276. SendMessage(hwnd, WM_GETTEXT, cchText + 1, (LPARAM)psz);
  277. if (!*psz)
  278. *pbstr = NULL;
  279. else
  280. {
  281. *pbstr = SysAllocString(psz);
  282. if (!*pbstr)
  283. hres = E_OUTOFMEMORY;
  284. }
  285. // free memory if memory was allocated from heap
  286. if (psz != sz)
  287. delete [] psz;
  288. return hres;
  289. }
  290. // --------------------------------------------------------------------------
  291. //
  292. // HRESULT GetLabelString(HWND hwnd, BSTR* pbstr)
  293. //
  294. // This walks backwards among peer windows to find a static field. It stops
  295. // if it gets to the front or hits a group/tabstop, just like the dialog
  296. // manager does.
  297. //
  298. // RETURN:
  299. // HRESULT ? S_OK on success : S_FALSE or COM error on failure
  300. // --------------------------------------------------------------------------
  301. HRESULT GetLabelString(HWND hwnd, BSTR* pbstr)
  302. {
  303. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetLabelString");
  304. HWND hwndLabel = hwnd;
  305. while (hwndLabel = ::GetWindow(hwndLabel, GW_HWNDPREV))
  306. {
  307. LONG lStyle = GetWindowLong(hwndLabel, GWL_STYLE);
  308. // Skip if invisible
  309. if (!(lStyle & WS_VISIBLE))
  310. continue;
  311. // Is this a static dude?
  312. LRESULT lResult = SendMessage(hwndLabel, WM_GETDLGCODE, 0, 0L);
  313. if (lResult & DLGC_STATIC)
  314. {
  315. // Great, we've found our label.
  316. return GetTextString(hwndLabel, pbstr);
  317. }
  318. // Is this a tabstop or group? If so, bail out now.
  319. if (lStyle & (WS_GROUP | WS_TABSTOP))
  320. break;
  321. }
  322. return S_FALSE;
  323. }
  324. // --------------------------------------------------------------------------
  325. //
  326. // HRESULT StripMnemonic(BSTR bstrSrc, WCHAR** pchAmp, BOOL bStopOnAmp)
  327. //
  328. // This removes the mnemonic prefix. However, if we see '&&', we keep
  329. // one '&'.
  330. //
  331. // --------------------------------------------------------------------------
  332. HRESULT StripMnemonic(BSTR bstrSrc, WCHAR** pchAmp, BOOL bStopOnAmp)
  333. {
  334. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "StripMnemonic");
  335. const WCHAR amp = L'&';
  336. if (pchAmp)
  337. pchAmp = NULL;
  338. WCHAR *psz = (WCHAR*)bstrSrc;
  339. while (*psz)
  340. {
  341. if (*psz == amp)
  342. {
  343. if (*(psz + 1) == amp)
  344. psz++;
  345. else
  346. {
  347. if (pchAmp)
  348. *pchAmp = psz;
  349. break;
  350. }
  351. }
  352. psz++;
  353. }
  354. // Start moving all the character up 1 position
  355. if (!bStopOnAmp)
  356. while (*psz)
  357. *psz = *++psz;
  358. return(S_OK);
  359. }
  360. // --------------------------------------------------------------------------
  361. //
  362. // HRESULT GetWindowName(HWND hwnd, BSTR* pbstrName)
  363. //
  364. // --------------------------------------------------------------------------
  365. HRESULT GetWindowName(HWND hwnd, BSTR* pbstrName)
  366. {
  367. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetWindowName");
  368. // If use a label, do that instead
  369. if (S_OK != GetLabelString(hwnd, pbstrName) || !*pbstrName)
  370. return S_FALSE;
  371. // Strip out the mnemonic.
  372. return StripMnemonic(*pbstrName, NULL, FALSE);
  373. }
  374. // --------------------------------------------------------------------------
  375. //
  376. // HRESULT GetWindowShortcut(HWND hwnd, BSTR* pbstrShortcut)
  377. //
  378. // --------------------------------------------------------------------------
  379. HRESULT GetWindowShortcut(HWND hwnd, BSTR* pbstrShortcut)
  380. {
  381. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "GetWindowShortcut");
  382. if (S_OK != GetLabelString(hwnd, pbstrShortcut) || !*pbstrShortcut)
  383. return S_FALSE;
  384. WCHAR *pch;
  385. StripMnemonic(*pbstrShortcut, &pch, TRUE);
  386. // Is there a mnemonic?
  387. if (pch)
  388. {
  389. // Get a localized "Alt+" string
  390. BSTR pbstrAlt = NULL;
  391. HRESULT hr = GetStringResource(STR_ALT, &pbstrAlt);
  392. if (hr != S_OK || !pbstrAlt)
  393. return hr;
  394. // Make a string of the form "Alt+ch".
  395. WCHAR szKey[MAX_PATH];
  396. wcsncpy (szKey, pbstrAlt, MAX_PATH);
  397. WCHAR *pchTemp = szKey + wcslen(szKey);
  398. // Copy shortcut character
  399. *pchTemp = *pch;
  400. *(++pchTemp) = L'\0';
  401. // Release allocated string allocate space for new string
  402. SysFreeString(pbstrAlt);
  403. *pbstrShortcut = SysAllocString(pchTemp);
  404. return (*pbstrShortcut ? S_OK : E_OUTOFMEMORY);
  405. }
  406. return(S_FALSE);
  407. }
  408. // --------------------------------------------------------------------------
  409. //
  410. // GetWindowObject()
  411. //
  412. // Gets an immediate child object.
  413. //
  414. // --------------------------------------------------------------------------
  415. HRESULT GetWindowObject(HWND hwndChild, VARIANT * pvar)
  416. {
  417. pvar->vt = VT_EMPTY;
  418. IDispatch * pdispChild = NULL;
  419. HRESULT hr = W32->AccessibleObjectFromWindow(hwndChild, OBJID_WINDOW, IID_IDispatch,
  420. (void **)&pdispChild);
  421. if (!SUCCEEDED(hr))
  422. return(hr);
  423. if (!pdispChild)
  424. return(E_FAIL);
  425. pvar->vt = VT_DISPATCH;
  426. pvar->pdispVal = pdispChild;
  427. return(S_OK);
  428. }
  429. } //namespace
  430. //////////////////////// ListBox CListBoxSelection Methods ///////////////////////////
  431. // --------------------------------------------------------------------------
  432. //
  433. // CListBoxSelection::CListBoxSelection()
  434. //
  435. // We AddRef() once plistFrom so that it won't go away out from us. When
  436. // we are destroyed, we will Release() it.
  437. //
  438. // --------------------------------------------------------------------------
  439. CListBoxSelection::CListBoxSelection(int iChildCur, int cSelected, LPINT lpSelection)
  440. {
  441. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::CListBoxSelection");
  442. _idChildCur = iChildCur;
  443. _cRef = 1;
  444. _piSel = new int[cSelected];
  445. if (!_piSel)
  446. _cSel = 0;
  447. else
  448. {
  449. _cSel = cSelected;
  450. memcpy(_piSel, lpSelection, cSelected*sizeof(int));
  451. }
  452. }
  453. // --------------------------------------------------------------------------
  454. //
  455. // CListBoxSelection::~CListBoxSelection()
  456. //
  457. // --------------------------------------------------------------------------
  458. CListBoxSelection::~CListBoxSelection()
  459. {
  460. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::~CListBoxSelection");
  461. // Free item memory
  462. if (_piSel)
  463. {
  464. delete [] _piSel;
  465. _piSel = NULL;
  466. }
  467. }
  468. // --------------------------------------------------------------------------
  469. //
  470. // CListBoxSelection::QueryInterface()
  471. //
  472. // We only respond to IUnknown and IEnumVARIANT! It is the responsibility
  473. // of the caller to loop through the items using IEnumVARIANT interfaces,
  474. // and get the child IDs to then pass to the parent object (or call
  475. // directly if VT_DISPATCH--not in this case they aren't though).
  476. //
  477. // --------------------------------------------------------------------------
  478. STDMETHODIMP CListBoxSelection::QueryInterface(REFIID riid, void** ppunk)
  479. {
  480. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::QueryInterface");
  481. *ppunk = NULL;
  482. if ((riid == IID_IUnknown) || (riid == IID_IEnumVARIANT))
  483. {
  484. *ppunk = this;
  485. }
  486. else
  487. return(E_NOINTERFACE);
  488. ((LPUNKNOWN) *ppunk)->AddRef();
  489. return(S_OK);
  490. }
  491. // --------------------------------------------------------------------------
  492. //
  493. // CListBoxSelection::AddRef()
  494. //
  495. // --------------------------------------------------------------------------
  496. STDMETHODIMP_(ULONG) CListBoxSelection::AddRef(void)
  497. {
  498. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::AddRef");
  499. return(++_cRef);
  500. }
  501. // --------------------------------------------------------------------------
  502. //
  503. // CListBoxSelection::Release()
  504. //
  505. // --------------------------------------------------------------------------
  506. STDMETHODIMP_(ULONG) CListBoxSelection::Release(void)
  507. {
  508. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::Release");
  509. if ((--_cRef) == 0)
  510. {
  511. delete this;
  512. return 0;
  513. }
  514. return(_cRef);
  515. }
  516. // --------------------------------------------------------------------------
  517. //
  518. // CListBoxSelection::Next()
  519. //
  520. // This returns a VT_I4 which is the child ID for the parent listbox that
  521. // returned this object for the selection collection. The caller turns
  522. // around and passes this variant to the listbox object to get acc info
  523. // about it.
  524. //
  525. // --------------------------------------------------------------------------
  526. STDMETHODIMP CListBoxSelection::Next(ULONG celt, VARIANT* rgvar, ULONG *pceltFetched)
  527. {
  528. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::Next");
  529. // Can be NULL
  530. if (pceltFetched)
  531. *pceltFetched = 0;
  532. // reset temporary variable to beginning
  533. VARIANT *pvar = rgvar;
  534. long cFetched = 0;
  535. long iCur = _idChildCur;
  536. // Loop through our items
  537. while ((cFetched < (long)celt) && (iCur < _cSel))
  538. {
  539. VariantInit(pvar);
  540. pvar->vt = VT_I4;
  541. pvar->lVal = _piSel[iCur] + 1;
  542. cFetched++;
  543. iCur++;
  544. pvar++;
  545. }
  546. // Initialize the variant after the last valid one just
  547. // in case the client is looping based on invalid variants
  548. if ((ULONG)cFetched < celt)
  549. VariantInit(pvar);
  550. // Advance the current position
  551. _idChildCur = iCur;
  552. // Fill in the number fetched
  553. if (pceltFetched)
  554. *pceltFetched = cFetched;
  555. // Return S_FALSE if we grabbed fewer items than requested
  556. return((cFetched < (long)celt) ? S_FALSE : S_OK);
  557. }
  558. // --------------------------------------------------------------------------
  559. //
  560. // CListBoxSelection::Skip()
  561. //
  562. // -------------------------------------------------------------------------
  563. STDMETHODIMP CListBoxSelection::Skip(ULONG celt)
  564. {
  565. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::Skip");
  566. _idChildCur += celt;
  567. if (_idChildCur > _cSel)
  568. _idChildCur = _cSel;
  569. // We return S_FALSE if at the end.
  570. return((_idChildCur >= _cSel) ? S_FALSE : S_OK);
  571. }
  572. // --------------------------------------------------------------------------
  573. //
  574. // CListBoxSelection::Reset()
  575. //
  576. // --------------------------------------------------------------------------
  577. STDMETHODIMP CListBoxSelection::Reset(void)
  578. {
  579. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::Reset");
  580. _idChildCur = 0;
  581. return(S_OK);
  582. }
  583. // --------------------------------------------------------------------------
  584. //
  585. // CListBoxSelection::Clone()
  586. //
  587. // --------------------------------------------------------------------------
  588. STDMETHODIMP CListBoxSelection::Clone(IEnumVARIANT **ppenum)
  589. {
  590. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CListBoxSelection::Clone");
  591. InitPv(ppenum);
  592. CListBoxSelection * plistselnew = new CListBoxSelection(_idChildCur, _cSel, _piSel);
  593. if (!plistselnew)
  594. return(E_OUTOFMEMORY);
  595. return(plistselnew->QueryInterface(IID_IEnumVARIANT, (void**)ppenum));
  596. }
  597. //////////////////////// ListBox IAccessible Methods //////////////////////////////
  598. /*
  599. * CLstBxWinHost::InitTypeInfo()
  600. *
  601. * @mfunc
  602. * Retrieves type library
  603. *
  604. * @rdesc
  605. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  606. * otherwise.
  607. */
  608. HRESULT CLstBxWinHost::InitTypeInfo()
  609. {
  610. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::InitTypeInfo");
  611. return MSAA::InitTypeInfo(&_pTypeInfo);
  612. }
  613. /*
  614. * CLstBxWinHost::get_accName(VARIANT varChild, BSTR *pbstrName)
  615. *
  616. * @mfunc
  617. * SELF ? label of control : item text
  618. *
  619. * @rdesc
  620. * HRESULT = S_FALSE.
  621. */
  622. STDMETHODIMP CLstBxWinHost::get_accName(VARIANT varChild, BSTR *pbstrName)
  623. {
  624. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accName");
  625. InitPv(pbstrName);
  626. // Validate parameters
  627. if (!MSAA::ValidateChild(&varChild, GetCount()))
  628. return(E_INVALIDARG);
  629. if (varChild.lVal == CHILDID_SELF)
  630. {
  631. if (_fLstType == kCombo)
  632. return _pcbHost->get_accName(varChild, pbstrName);
  633. else
  634. return(MSAA::GetWindowName(_hwnd, pbstrName));
  635. }
  636. else
  637. {
  638. // Get the item text.
  639. LRESULT lres = RichListBoxWndProc(_hwnd, LB_GETTEXTLEN, varChild.lVal-1, 0);
  640. // First Check for error
  641. if (lres == LB_ERR)
  642. return S_FALSE;
  643. if (lres > 0)
  644. {
  645. // allocate some buffer
  646. *pbstrName = SysAllocStringLen(NULL, lres + 1);
  647. if (!*pbstrName)
  648. return E_OUTOFMEMORY;
  649. RichListBoxWndProc(_hwnd, LB_GETTEXT, varChild.lVal-1, (LPARAM)*pbstrName);
  650. }
  651. }
  652. return(S_OK);
  653. }
  654. /*
  655. * CLstBxWinHost::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  656. *
  657. * @mfunc
  658. * Retrieves the object's Role property.
  659. *
  660. * @rdesc
  661. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  662. * otherwise.
  663. */
  664. STDMETHODIMP CLstBxWinHost::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  665. {
  666. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accRole");
  667. InitPvar(pvarRole);
  668. // Validate parameters
  669. if (!MSAA::ValidateChild(&varChild, GetCount()))
  670. return E_INVALIDARG;
  671. pvarRole->vt = VT_I4;
  672. if (varChild.lVal)
  673. pvarRole->lVal = ROLE_SYSTEM_LISTITEM;
  674. else
  675. pvarRole->lVal = ROLE_SYSTEM_LIST;
  676. return S_OK;
  677. }
  678. /*
  679. * CLstBxWinHost::get_accState(VARIANT varChild, VARIANT *pvarState)
  680. *
  681. * @mfunc
  682. * Retrieves the current state of the object or child item.
  683. *
  684. * @rdesc
  685. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  686. * otherwise.
  687. */
  688. STDMETHODIMP CLstBxWinHost::get_accState(VARIANT varChild, VARIANT *pvarState)
  689. {
  690. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accState");
  691. // Validate parameters
  692. if (!MSAA::ValidateChild(&varChild, GetCount()))
  693. return E_INVALIDARG;
  694. InitPvar(pvarState);
  695. if (varChild.lVal == CHILDID_SELF)
  696. {
  697. pvarState->vt = VT_I4;
  698. pvarState->lVal = 0;
  699. if (!IsWindowVisible(_hwnd))
  700. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  701. if (!IsWindowEnabled(_hwnd))
  702. pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE;
  703. if (_fFocus)
  704. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  705. if (::GetForegroundWindow() == MSAA::GetAncestor(_hwnd, GA_ROOT))
  706. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  707. return S_OK;
  708. }
  709. --varChild.lVal;
  710. pvarState->vt = VT_I4;
  711. pvarState->lVal = 0;
  712. // Is this item selected?
  713. if (IsSelected(varChild.lVal))
  714. pvarState->lVal |= STATE_SYSTEM_SELECTED;
  715. // Does it have the focus? Remember that we decremented the lVal so it
  716. // is zero-based like listbox indeces.
  717. if (_fFocus)
  718. {
  719. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  720. if (varChild.lVal == GetCursor())
  721. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  722. }
  723. // Is the listbox read-only?
  724. long lStyle = GetWindowLong(_hwnd, GWL_STYLE);
  725. if (lStyle & LBS_NOSEL)
  726. pvarState->lVal |= STATE_SYSTEM_READONLY;
  727. else
  728. {
  729. pvarState->lVal |= STATE_SYSTEM_SELECTABLE;
  730. // Is the listbox multiple and/or extended sel? NOTE: We have
  731. // no way to implement accSelect() EXTENDSELECTION so don't.
  732. if (lStyle & LBS_MULTIPLESEL)
  733. pvarState->lVal |= STATE_SYSTEM_MULTISELECTABLE;
  734. }
  735. // Is the item in view?
  736. //
  737. // SMD 09/16/97 Offscreen things are things never on the screen,
  738. // and that doesn't apply to this. Changed from OFFSCREEN to
  739. // INVISIBLE.
  740. RECT rcItem;
  741. if (!RichListBoxWndProc(_hwnd, LB_GETITEMRECT, varChild.lVal, (LPARAM)&rcItem))
  742. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  743. return S_OK;
  744. }
  745. /*
  746. * CLstBxWinHost::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszShortcut)
  747. *
  748. * @mfunc
  749. * Retrieves an object's KeyboardShortcut property.
  750. *
  751. * @rdesc
  752. * Returns S_OK if successful or one of the following values or a standard COM
  753. * error code otherwise.
  754. */
  755. STDMETHODIMP CLstBxWinHost::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszShortcut)
  756. {
  757. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accKeyboardShortcut");
  758. // Validate
  759. if (!MSAA::ValidateChild(&varChild, GetCount()))
  760. return(E_INVALIDARG);
  761. if ((varChild.lVal == 0) && _fLstType != kCombo)
  762. {
  763. InitPv(pszShortcut);
  764. return(MSAA::GetWindowShortcut(_hwnd, pszShortcut));
  765. }
  766. return(DISP_E_MEMBERNOTFOUND);
  767. }
  768. /*
  769. * CLstBxWinHost::get_accFocus(VARIANT *pvarChild)
  770. *
  771. * @mfunc
  772. * Retrieves the child object that currently has the keyboard focus.
  773. *
  774. * @rdesc
  775. * Returns S_OK if successful or one of the following values or a standard COM
  776. * error code otherwise.
  777. */
  778. STDMETHODIMP CLstBxWinHost::get_accFocus(VARIANT *pvarChild)
  779. {
  780. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accFocus");
  781. InitPvar(pvarChild);
  782. // Are we the focus?
  783. if (_fFocus)
  784. {
  785. pvarChild->vt = VT_I4;
  786. if (GetCursor() >= 0)
  787. pvarChild->lVal = GetCursor() + 1;
  788. else
  789. pvarChild->lVal = 0;
  790. return S_OK;
  791. }
  792. else
  793. return S_FALSE;
  794. }
  795. /*
  796. * CLstBxWinHost::get_accSelection(VARIANT *pvarSelection)
  797. *
  798. * @mfunc
  799. * Retrieves the selected children of this object.
  800. *
  801. * @rdesc
  802. * Returns S_OK if successful or one of the following values or a standard COM
  803. * error code otherwise.
  804. */
  805. STDMETHODIMP CLstBxWinHost::get_accSelection(VARIANT *pvarSelection)
  806. {
  807. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accSelection");
  808. InitPvar(pvarSelection);
  809. int cSel = RichListBoxWndProc(_hwnd, LB_GETSELCOUNT, 0, 0);
  810. if (cSel <= 1)
  811. {
  812. // cSelected is -1, 0, or 1.
  813. // -1 means this is a single sel listbox.
  814. // 0 or 1 means this is multisel
  815. if (GetCursor() < 0)
  816. return S_FALSE;
  817. pvarSelection->vt = VT_I4;
  818. pvarSelection->lVal = GetCursor() + 1;
  819. return(S_OK);
  820. }
  821. // Allocate memory for the list of item IDs
  822. int * plbs = new int[cSel];
  823. if (!plbs)
  824. return(E_OUTOFMEMORY);
  825. // Multiple items; must make a collection
  826. // Get the list of selected item IDs
  827. int j = 0;
  828. for (long i = 0; i < GetCount(); i++)
  829. {
  830. if (IsSelected(i) == TRUE)
  831. plbs[j++] = i;
  832. }
  833. CListBoxSelection *plbsel = new CListBoxSelection(0, cSel, plbs);
  834. delete [] plbs;
  835. // check if memory allocation failed
  836. if (!plbsel)
  837. return(E_OUTOFMEMORY);
  838. pvarSelection->vt = VT_UNKNOWN;
  839. return plbsel->QueryInterface(IID_IUnknown, (void**)&(pvarSelection->punkVal));
  840. }
  841. /*
  842. * CLstBxWinHost::get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction)
  843. *
  844. * @mfunc
  845. * Retrieves a string containing a localized sentence that describes the object's default action.
  846. *
  847. * @rdesc
  848. * Returns S_OK if successful or one of the following values or a standard COM
  849. * error code otherwise.
  850. */
  851. STDMETHODIMP CLstBxWinHost::get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction)
  852. {
  853. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accDefaultAction");
  854. InitPv(pszDefAction);
  855. // Validate.
  856. if (!MSAA::ValidateChild(&varChild, GetCount()))
  857. return(E_INVALIDARG);
  858. if (varChild.lVal)
  859. return (MSAA::GetStringResource(STR_DOUBLE_CLICK, pszDefAction));
  860. return(DISP_E_MEMBERNOTFOUND);
  861. }
  862. /*
  863. * CLstBxWinHost::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
  864. *
  865. * @mfunc
  866. * Retrieves the object's current screen location (if the object was placed on
  867. * the screen) and optionally, the child element.
  868. *
  869. * @rdesc
  870. * Returns S_OK if successful or one of the following values or a standard COM
  871. * error code otherwise.
  872. */
  873. STDMETHODIMP CLstBxWinHost::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
  874. {
  875. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::accLocation");
  876. InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
  877. // Validate params
  878. if (!MSAA::ValidateChild(&varChild, GetCount()))
  879. return E_INVALIDARG;
  880. RECT rc;
  881. if (!varChild.lVal)
  882. GetClientRect(_hwnd, &rc);
  883. else if (!RichListBoxWndProc(_hwnd, LB_GETITEMRECT, varChild.lVal-1, (LPARAM)&rc))
  884. return S_OK;
  885. // Convert coordinates to screen coordinates
  886. *pcxWidth = rc.right - rc.left;
  887. *pcyHeight = rc.bottom - rc.top;
  888. ClientToScreen(_hwnd, (LPPOINT)&rc);
  889. *pxLeft = rc.left;
  890. *pyTop = rc.top;
  891. return S_OK;
  892. }
  893. /*
  894. * CLstBxWinHost::accHitTest(long xLeft, long yTop, VARIANT *pvarHit)
  895. *
  896. * @mfunc
  897. * Retrieves the child object at a given point on the screen.
  898. *
  899. * @rdesc
  900. * Returns S_OK if successful or one of the following values or a standard COM
  901. * error code otherwise.
  902. */
  903. STDMETHODIMP CLstBxWinHost::accHitTest(long xLeft, long yTop, VARIANT *pvarHit)
  904. {
  905. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::accHitTest");
  906. InitPvar(pvarHit);
  907. // Is the point in our client area?
  908. POINT pt = {xLeft, yTop};
  909. ScreenToClient(_hwnd, &pt);
  910. RECT rc;
  911. GetClientRect(_hwnd, &rc);
  912. if (!PtInRect(&rc, pt))
  913. return(S_FALSE);
  914. // What item is here?
  915. long l = GetItemFromPoint(&pt);
  916. pvarHit->vt = VT_I4;
  917. pvarHit->lVal = (l >= 0) ? l + 1 : 0;
  918. return(S_OK);
  919. }
  920. /*
  921. * CLstBxWinHost::accDoDefaultAction(VARIANT varChild)
  922. *
  923. * @mfunc
  924. * Performs the object's default action.
  925. *
  926. * @rdesc
  927. * Returns S_OK if successful or one of the following values or a standard COM
  928. * error code otherwise.
  929. */
  930. STDMETHODIMP CLstBxWinHost::accDoDefaultAction(VARIANT varChild)
  931. {
  932. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::accDoDefaultAction");
  933. // Validate
  934. if (!MSAA::ValidateChild(&varChild, GetCount()))
  935. return(E_INVALIDARG);
  936. if (varChild.lVal)
  937. {
  938. // this will check if WindowFromPoint at the click point is the same
  939. // as m_hwnd, and if not, it won't click. Cool!
  940. RECT rcLoc;
  941. HRESULT hr = accLocation(&rcLoc.left, &rcLoc.top, &rcLoc.right, &rcLoc.bottom, varChild);
  942. if (!SUCCEEDED (hr))
  943. return (hr);
  944. // Find Center of rect
  945. POINT ptClick;
  946. ptClick.x = rcLoc.left + (rcLoc.right/2);
  947. ptClick.y = rcLoc.top + (rcLoc.bottom/2);
  948. // check if hwnd at point is same as hwnd to check
  949. if (WindowFromPoint(ptClick) != _hwnd)
  950. return DISP_E_MEMBERNOTFOUND;
  951. W32->BlockInput(TRUE);
  952. // Get current cursor pos.
  953. POINT ptCursor;
  954. DWORD dwMouseDown, dwMouseUp;
  955. GetCursorPos(&ptCursor);
  956. if (GetSystemMetrics(SM_SWAPBUTTON))
  957. {
  958. dwMouseDown = MOUSEEVENTF_RIGHTDOWN;
  959. dwMouseUp = MOUSEEVENTF_RIGHTUP;
  960. }
  961. else
  962. {
  963. dwMouseDown = MOUSEEVENTF_LEFTDOWN;
  964. dwMouseUp = MOUSEEVENTF_LEFTUP;
  965. }
  966. // Get delta to move to center of rectangle from current
  967. // cursor location.
  968. ptCursor.x = ptClick.x - ptCursor.x;
  969. ptCursor.y = ptClick.y - ptCursor.y;
  970. // NOTE: For relative moves, USER actually multiplies the
  971. // coords by any acceleration. But accounting for it is too
  972. // hard and wrap around stuff is weird. So, temporarily turn
  973. // acceleration off; then turn it back on after playback.
  974. // Save mouse acceleration info
  975. MOUSEINFO miSave, miNew;
  976. if (!SystemParametersInfo(SPI_GETMOUSE, 0, &miSave, 0))
  977. {
  978. W32->BlockInput(FALSE);
  979. return (DISP_E_MEMBERNOTFOUND);
  980. }
  981. if (miSave.MouseSpeed)
  982. {
  983. miNew.MouseThresh1 = 0;
  984. miNew.MouseThresh2 = 0;
  985. miNew.MouseSpeed = 0;
  986. if (!SystemParametersInfo(SPI_SETMOUSE, 0, &miNew, 0))
  987. {
  988. W32->BlockInput(FALSE);
  989. return (DISP_E_MEMBERNOTFOUND);
  990. }
  991. }
  992. // Get # of buttons
  993. int nButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
  994. // mouse move to center of start button
  995. INPUT rgInput[6];
  996. rgInput[0].type = INPUT_MOUSE;
  997. rgInput[0].mi.dwFlags = MOUSEEVENTF_MOVE;
  998. rgInput[0].mi.dwExtraInfo = 0;
  999. rgInput[0].mi.dx = ptCursor.x;
  1000. rgInput[0].mi.dy = ptCursor.y;
  1001. rgInput[0].mi.mouseData = nButtons;
  1002. int i = 1;
  1003. // MSAA's order of double click is
  1004. // WM_LBUTTONDOWN
  1005. // WM_LBUTTONUP
  1006. // WM_LBUTTONDOWN
  1007. // WM_LBUTTONUP
  1008. while (i <= 4)
  1009. {
  1010. if (i % 2)
  1011. rgInput[i].mi.dwFlags = dwMouseDown;
  1012. else
  1013. rgInput[i].mi.dwFlags = dwMouseUp;
  1014. rgInput[i].type = INPUT_MOUSE;
  1015. rgInput[i].mi.dwExtraInfo = 0;
  1016. rgInput[i].mi.dx = 0;
  1017. rgInput[i].mi.dy = 0;
  1018. rgInput[i].mi.mouseData = nButtons;
  1019. i++;
  1020. }
  1021. // move mouse back to starting location
  1022. rgInput[i].type = INPUT_MOUSE;
  1023. rgInput[i].mi.dwFlags = MOUSEEVENTF_MOVE;
  1024. rgInput[i].mi.dwExtraInfo = 0;
  1025. rgInput[i].mi.dx = -ptCursor.x;
  1026. rgInput[i].mi.dy = -ptCursor.y;
  1027. rgInput[i].mi.mouseData = nButtons;
  1028. i++;
  1029. if (!W32->SendInput(i, rgInput, sizeof(INPUT)))
  1030. MessageBeep(0);
  1031. // Restore Mouse Acceleration
  1032. if (miSave.MouseSpeed)
  1033. SystemParametersInfo(SPI_SETMOUSE, 0, &miSave, 0);
  1034. W32->BlockInput (FALSE);
  1035. return (S_OK);
  1036. }
  1037. return(DISP_E_MEMBERNOTFOUND);
  1038. }
  1039. /*
  1040. * CLstBxWinHost::accSelect(long selFlags, VARIANT varChild)
  1041. *
  1042. * @mfunc
  1043. * Modifies the selection or moves the keyboard focus according to the specified flags.
  1044. *
  1045. * @rdesc
  1046. * Returns S_OK if successful or one of the following values or a standard COM
  1047. * error code otherwise.
  1048. */
  1049. STDMETHODIMP CLstBxWinHost::accSelect(long selFlags, VARIANT varChild)
  1050. {
  1051. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::accSelect");
  1052. // Validate parameters
  1053. if (!MSAA::ValidateChild(&varChild, GetCount()) || !MSAA::ValidateSelFlags(selFlags))
  1054. return(E_INVALIDARG);
  1055. if (!varChild.lVal)
  1056. return(S_FALSE);
  1057. varChild.lVal--;
  1058. long lStyle = GetWindowLong(_hwnd, GWL_STYLE);
  1059. if (lStyle & LBS_NOSEL)
  1060. return DISP_E_MEMBERNOTFOUND;
  1061. if (!IsSingleSelection())
  1062. {
  1063. // get the focused item here in case we change it.
  1064. int nFocusedItem = GetCursor();
  1065. if (selFlags & SELFLAG_TAKEFOCUS)
  1066. {
  1067. if (!_fFocus)
  1068. return(S_FALSE);
  1069. RichListBoxWndProc (_hwnd, LB_SETCARETINDEX, varChild.lVal, 0);
  1070. }
  1071. // reset and select requested item
  1072. if (selFlags & SELFLAG_TAKESELECTION)
  1073. {
  1074. // deselect the whole range of items
  1075. RichListBoxWndProc(_hwnd, LB_SETSEL, FALSE, -1);
  1076. // Select this one
  1077. RichListBoxWndProc(_hwnd, LB_SETSEL, TRUE, varChild.lVal);
  1078. }
  1079. if (selFlags & SELFLAG_EXTENDSELECTION)
  1080. {
  1081. if ((selFlags & SELFLAG_ADDSELECTION) || (selFlags & SELFLAG_REMOVESELECTION))
  1082. RichListBoxWndProc (_hwnd, LB_SELITEMRANGE, (selFlags & SELFLAG_ADDSELECTION),
  1083. MAKELPARAM(nFocusedItem, varChild.lVal));
  1084. else
  1085. {
  1086. BOOL bSelected = RichListBoxWndProc (_hwnd, LB_GETSEL, nFocusedItem, 0);
  1087. RichListBoxWndProc (_hwnd, LB_SELITEMRANGE, bSelected, MAKELPARAM(nFocusedItem,varChild.lVal));
  1088. }
  1089. }
  1090. else // not extending, check add/remove
  1091. {
  1092. if ((selFlags & SELFLAG_ADDSELECTION) || (selFlags & SELFLAG_REMOVESELECTION))
  1093. RichListBoxWndProc(_hwnd, LB_SETSEL, (selFlags & SELFLAG_ADDSELECTION), varChild.lVal);
  1094. }
  1095. // set focus to where it was before if SELFLAG_TAKEFOCUS not set
  1096. if ((selFlags & SELFLAG_TAKEFOCUS) == 0)
  1097. RichListBoxWndProc (_hwnd, LB_SETCARETINDEX, nFocusedItem, 0);
  1098. }
  1099. else // listbox is single select
  1100. {
  1101. if (selFlags & (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION | SELFLAG_EXTENDSELECTION))
  1102. return (E_INVALIDARG);
  1103. // single select listboxes do not allow you to set the
  1104. // focus independently of the selection, so we send a
  1105. // LB_SETCURSEL for both TAKESELECTION and TAKEFOCUS
  1106. if ((selFlags & SELFLAG_TAKESELECTION) || (selFlags & SELFLAG_TAKEFOCUS))
  1107. RichListBoxWndProc(_hwnd, LB_SETCURSEL, varChild.lVal, 0);
  1108. } // end if listbox is single select
  1109. return(S_OK);
  1110. }
  1111. /*
  1112. * CLstBxWinHost::accNavigate(long dwNavDir, VARIANT varStart, VARIANT *pvarEnd)
  1113. *
  1114. * @mfunc
  1115. * Retrieves the next or previous sibling or child object in a specified direction.
  1116. *
  1117. * @rdesc
  1118. * Returns S_OK if successful or one of the following values or a standard COM
  1119. * error code otherwise.
  1120. */
  1121. STDMETHODIMP CLstBxWinHost::accNavigate(long dwNavDir, VARIANT varStart, VARIANT *pvarEnd)
  1122. {
  1123. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::accNavigate");
  1124. InitPvar(pvarEnd);
  1125. // Validate parameters
  1126. if (!MSAA::ValidateChild(&varStart, GetCount()))
  1127. return(E_INVALIDARG);
  1128. // Is this something for the client (or combobox) to handle?
  1129. long lEnd = 0;
  1130. if (dwNavDir == NAVDIR_FIRSTCHILD)
  1131. {
  1132. lEnd = GetCount() ? 1 : 0;
  1133. }
  1134. else if (dwNavDir == NAVDIR_LASTCHILD)
  1135. lEnd = GetCount();
  1136. else if (varStart.lVal == CHILDID_SELF)
  1137. {
  1138. // NOTE:
  1139. // MSAA tries to make a distinction for controls by implementing 2 different types of
  1140. // interfaces for controls.
  1141. // OBJID_WINDOW - will include the windows border along with the client. This control
  1142. // should be perceived from a dialog or some window containers perspective.
  1143. // Where the control is just an abstract entity contained in the window container
  1144. // OBJID_CLIENT - only includes the client area. This interface is only concerned with
  1145. // the control itself and disregards the outside world
  1146. IAccessible* poleacc = NULL;
  1147. HRESULT hr = W32->AccessibleObjectFromWindow(_hwnd, OBJID_WINDOW, IID_IAccessible, (void**)&poleacc);
  1148. if (!SUCCEEDED(hr))
  1149. return(hr);
  1150. // Ask it to navigate
  1151. VARIANT varStart;
  1152. VariantInit(&varStart);
  1153. varStart.vt = VT_I4;
  1154. varStart.lVal = OBJID_CLIENT;
  1155. hr = poleacc->accNavigate(dwNavDir, varStart, pvarEnd);
  1156. // Release our parent
  1157. poleacc->Release();
  1158. return(hr);
  1159. }
  1160. else
  1161. {
  1162. //long lT = varStart.lVal - 1;
  1163. switch (dwNavDir)
  1164. {
  1165. // We're a single column list box only so ignore
  1166. // these flags
  1167. //case NAVDIR_RIGHT:
  1168. //case NAVDIR_LEFT:
  1169. // break;
  1170. case NAVDIR_PREVIOUS:
  1171. case NAVDIR_UP:
  1172. // Are we in the top-most row?
  1173. lEnd = varStart.lVal - 1;
  1174. break;
  1175. case NAVDIR_NEXT:
  1176. case NAVDIR_DOWN:
  1177. lEnd = varStart.lVal + 1;
  1178. if (lEnd > GetCount())
  1179. lEnd = 0;
  1180. break;
  1181. }
  1182. }
  1183. if (lEnd)
  1184. {
  1185. pvarEnd->vt = VT_I4;
  1186. pvarEnd->lVal = lEnd;
  1187. }
  1188. return(lEnd ? S_OK : S_FALSE);
  1189. }
  1190. /*
  1191. * CLstBxWinHost::get_accParent(IDispatch **ppdispParent)
  1192. *
  1193. * @mfunc
  1194. * Retrieves the IDispatch interface of the current object's parent.
  1195. * Return S_FALSE and set the variable at ppdispParent to NULL.
  1196. *
  1197. * @rdesc
  1198. * HRESULT = S_FALSE.
  1199. */
  1200. STDMETHODIMP CLstBxWinHost::get_accParent(IDispatch **ppdispParent)
  1201. {
  1202. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accParent");
  1203. AssertSz(ppdispParent != NULL, "null pointer");
  1204. if (ppdispParent == NULL)
  1205. return S_FALSE;
  1206. InitPv(ppdispParent);
  1207. HWND hwnd;
  1208. if (_fLstType != kCombo)
  1209. {
  1210. hwnd = MSAA::GetAncestor(_hwnd, GA_PARENT);
  1211. AssertSz(hwnd, "Invalid Hwnd");
  1212. if (!hwnd)
  1213. return S_FALSE;
  1214. }
  1215. else
  1216. {
  1217. if (_pcbHost)
  1218. {
  1219. hwnd = _pcbHost->_hwnd;
  1220. Assert(hwnd);
  1221. }
  1222. else
  1223. return S_FALSE;
  1224. }
  1225. HRESULT hr = W32->AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, IID_IDispatch,
  1226. (void **)ppdispParent);
  1227. #ifdef DEBUG
  1228. if (FAILED(hr))
  1229. Assert(FALSE);
  1230. #endif
  1231. return hr;
  1232. }
  1233. /*
  1234. * CLstBxWinHost::get_accChildCount(long *pcCount)
  1235. *
  1236. * @mfunc
  1237. * Retrieves the number of children belonging to the current object.
  1238. *
  1239. * @rdesc
  1240. * HRESULT = S_FALSE.
  1241. */
  1242. STDMETHODIMP CLstBxWinHost::get_accChildCount(long *pcCount)
  1243. {
  1244. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CLstBxWinHost::get_accChildCount");
  1245. *pcCount = GetCount();
  1246. return(S_OK);
  1247. }
  1248. //////////////////////// Combobox IAccessible Methods //////////////////////////////
  1249. // COMBOBOXES
  1250. #define INDEX_COMBOBOX 0
  1251. #define INDEX_COMBOBOX_ITEM 1
  1252. #define INDEX_COMBOBOX_BUTTON 2
  1253. #define INDEX_COMBOBOX_LIST 3
  1254. #define CCHILDREN_COMBOBOX 3
  1255. /*
  1256. * CCmbBxWinHost::InitTypeInfo()
  1257. *
  1258. * @mfunc
  1259. * Retrieves type library
  1260. *
  1261. * @rdesc
  1262. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1263. * otherwise.
  1264. */
  1265. HRESULT CCmbBxWinHost::InitTypeInfo()
  1266. {
  1267. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::InitTypeInfo");
  1268. return MSAA::InitTypeInfo(&_pTypeInfo);
  1269. }
  1270. /*
  1271. * CCmbBxWinHost::get_accName(VARIANT varChild, BSTR *pszName)
  1272. *
  1273. * @mfunc
  1274. * Retrieves the Name property for this object.
  1275. *
  1276. * @rdesc
  1277. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1278. * otherwise.
  1279. */
  1280. STDMETHODIMP CCmbBxWinHost::get_accName(VARIANT varChild, BSTR *pszName)
  1281. {
  1282. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accName");
  1283. // Validate
  1284. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1285. return(E_INVALIDARG);
  1286. // The name of the combobox, the edit inside of it, and the dropdown
  1287. // are all the same. The name of the button is Drop down/Pop up
  1288. InitPv(pszName);
  1289. if (varChild.lVal != INDEX_COMBOBOX_BUTTON)
  1290. return(MSAA::GetWindowName(_hwnd, pszName));
  1291. else
  1292. {
  1293. if (IsWindowVisible(_hwndList))
  1294. return (MSAA::GetStringResource(STR_DROPDOWN_HIDE, pszName));
  1295. else
  1296. return(MSAA::GetStringResource(STR_DROPDOWN_SHOW, pszName));
  1297. }
  1298. }
  1299. /*
  1300. * CCmbBxWinHost::get_accValue(VARIANT varChild, BSTR *pszValue)
  1301. *
  1302. * @mfunc
  1303. * Retrieves the object's Value property.
  1304. *
  1305. * @rdesc
  1306. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1307. * otherwise.
  1308. */
  1309. STDMETHODIMP CCmbBxWinHost::get_accValue(VARIANT varChild, BSTR *pszValue)
  1310. {
  1311. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accValue");
  1312. // Validate
  1313. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1314. return(E_INVALIDARG);
  1315. switch (varChild.lVal)
  1316. {
  1317. case INDEX_COMBOBOX:
  1318. case INDEX_COMBOBOX_ITEM:
  1319. InitPv(pszValue);
  1320. LRESULT lres;
  1321. _pserv->TxSendMessage(WM_GETTEXTLENGTH, 0, 0, &lres);
  1322. // If windows text length is 0 then MSAA searches
  1323. // for the label associated with the control
  1324. if (lres <= 0)
  1325. return MSAA::GetLabelString(_hwnd, pszValue);
  1326. GETTEXTEX gt;
  1327. memset(&gt, 0, sizeof(GETTEXTEX));
  1328. gt.cb = (lres + 1) * sizeof(WCHAR);
  1329. gt.codepage = 1200;
  1330. gt.flags = GT_DEFAULT;
  1331. *pszValue = SysAllocStringLen(NULL, lres + 1);
  1332. if (!*pszValue)
  1333. return E_OUTOFMEMORY;
  1334. _pserv->TxSendMessage(EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)*pszValue, &lres);
  1335. return S_OK;
  1336. }
  1337. return DISP_E_MEMBERNOTFOUND;
  1338. }
  1339. /*
  1340. * CCmbBxWinHost::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  1341. *
  1342. * @mfunc
  1343. * Retrieves the object's Role property.
  1344. *
  1345. * @rdesc
  1346. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1347. * otherwise.
  1348. */
  1349. STDMETHODIMP CCmbBxWinHost::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  1350. {
  1351. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accRole");
  1352. // Validate--this does NOT accept a child ID.
  1353. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1354. return(E_INVALIDARG);
  1355. pvarRole->vt = VT_I4;
  1356. switch (varChild.lVal)
  1357. {
  1358. case INDEX_COMBOBOX:
  1359. pvarRole->lVal = ROLE_SYSTEM_COMBOBOX;
  1360. break;
  1361. case INDEX_COMBOBOX_ITEM:
  1362. if (_cbType == kDropDown)
  1363. pvarRole->lVal = ROLE_SYSTEM_TEXT;
  1364. else
  1365. pvarRole->lVal = ROLE_SYSTEM_STATICTEXT;
  1366. break;
  1367. case INDEX_COMBOBOX_BUTTON:
  1368. pvarRole->lVal = ROLE_SYSTEM_PUSHBUTTON;
  1369. break;
  1370. case INDEX_COMBOBOX_LIST:
  1371. pvarRole->lVal = ROLE_SYSTEM_LIST;
  1372. break;
  1373. default:
  1374. AssertSz(FALSE, "Invalid ChildID for child of combo box" );
  1375. }
  1376. return(S_OK);
  1377. }
  1378. /*
  1379. * CCmbBxWinHost::get_accState(VARIANT varChild, VARIANT *pvarState)
  1380. *
  1381. * @mfunc
  1382. * Retrieves the current state of the object or child item.
  1383. *
  1384. * @rdesc
  1385. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1386. * otherwise.
  1387. */
  1388. STDMETHODIMP CCmbBxWinHost::get_accState(VARIANT varChild, VARIANT *pvarState)
  1389. {
  1390. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accState");
  1391. // Validate--this does NOT accept a child ID.
  1392. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1393. return(E_INVALIDARG);
  1394. VARIANT var;
  1395. HRESULT hr;
  1396. IAccessible* poleacc;
  1397. InitPvar(pvarState);
  1398. pvarState->vt = VT_I4;
  1399. pvarState->lVal = 0;
  1400. HWND hwndActive = GetForegroundWindow();
  1401. switch (varChild.lVal)
  1402. {
  1403. case INDEX_COMBOBOX_BUTTON:
  1404. if (_fMousedown)
  1405. pvarState->lVal |= STATE_SYSTEM_PRESSED;
  1406. break;
  1407. case INDEX_COMBOBOX_ITEM:
  1408. if (_cbType == kDropDownList)
  1409. {
  1410. if (hwndActive == MSAA::GetAncestor(_hwnd, GA_ROOT))
  1411. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  1412. if (_fFocus)
  1413. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  1414. break;
  1415. }
  1416. // FALL THROUGH CASE
  1417. case INDEX_COMBOBOX:
  1418. if (!(_dwStyle & WS_VISIBLE))
  1419. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  1420. if (_dwStyle & WS_DISABLED)
  1421. pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE;
  1422. if (_fFocus)
  1423. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  1424. if (hwndActive == MSAA::GetAncestor(_hwnd, GA_ROOT))
  1425. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  1426. break;
  1427. case INDEX_COMBOBOX_LIST:
  1428. {
  1429. // First we incorporate the state of the window in general
  1430. //
  1431. VariantInit(&var);
  1432. if (FAILED(hr = MSAA::GetWindowObject(_hwndList, &var)))
  1433. return(hr);
  1434. Assert(var.vt == VT_DISPATCH);
  1435. // Get the child acc object
  1436. poleacc = NULL;
  1437. hr = var.pdispVal->QueryInterface(IID_IAccessible,
  1438. (void**)&poleacc);
  1439. var.pdispVal->Release();
  1440. if (FAILED(hr))
  1441. {
  1442. Assert(FALSE);
  1443. return(hr);
  1444. }
  1445. // Ask the child its state
  1446. VariantInit(&var);
  1447. hr = poleacc->get_accState(var, pvarState);
  1448. poleacc->Release();
  1449. if (FAILED(hr))
  1450. {
  1451. Assert(FALSE);
  1452. return(hr);
  1453. }
  1454. // The listbox is always going to be floating
  1455. //
  1456. pvarState->lVal |= STATE_SYSTEM_FLOATING;
  1457. if (_plbHost->_fDisabled)
  1458. pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE;
  1459. else
  1460. pvarState->lVal &= ~STATE_SYSTEM_UNAVAILABLE;
  1461. if (_fListVisible)
  1462. pvarState->lVal &= ~STATE_SYSTEM_INVISIBLE;
  1463. else
  1464. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  1465. break;
  1466. }
  1467. }
  1468. return(S_OK);
  1469. }
  1470. /*
  1471. * CCmbBxWinHost::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszShortcut)
  1472. *
  1473. * @mfunc
  1474. * Retrieves an object's KeyboardShortcut property.
  1475. *
  1476. * @rdesc
  1477. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1478. * otherwise.
  1479. */
  1480. STDMETHODIMP CCmbBxWinHost::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszShortcut)
  1481. {
  1482. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accKeyboardShortcut");
  1483. // Shortcut for combo is label's hotkey.
  1484. // Shortcut for dropdown (if button) is Alt+F4.
  1485. // CWO, 12/5/96, Alt+F4? F4, by itself brings down the combo box,
  1486. // but we add "Alt" to the string. Bad! Now use
  1487. // down arrow and add Alt to it via HrMakeShortcut()
  1488. // As documented in the UI style guide.
  1489. //
  1490. // As always, shortcuts only apply if the container has "focus". In other
  1491. // words, the hotkey for the combo does nothing if the parent dialog
  1492. // isn't active. And the hotkey for the dropdown does nothing if the
  1493. // combobox/edit isn't focused.
  1494. // Validate parameters
  1495. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1496. return(E_INVALIDARG);
  1497. InitPv(pszShortcut);
  1498. if (varChild.lVal == INDEX_COMBOBOX)
  1499. {
  1500. return(MSAA::GetWindowShortcut(_hwnd, pszShortcut));
  1501. }
  1502. else if (varChild.lVal == INDEX_COMBOBOX_BUTTON)
  1503. {
  1504. return(MSAA::GetStringResource(STR_COMBOBOX_LIST_SHORTCUT, pszShortcut));
  1505. }
  1506. return DISP_E_MEMBERNOTFOUND;
  1507. }
  1508. /*
  1509. * CCmbBxWinHost::get_accFocus(VARIANT *pvarFocus)
  1510. *
  1511. * @mfunc
  1512. * Retrieves the child object that currently has the keyboard focus.
  1513. *
  1514. * @rdesc
  1515. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1516. * otherwise.
  1517. */
  1518. STDMETHODIMP CCmbBxWinHost::get_accFocus(VARIANT *pvarFocus)
  1519. {
  1520. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accFocus");
  1521. InitPvar(pvarFocus);
  1522. // Is the current focus a child of us?
  1523. if (_fFocus)
  1524. {
  1525. pvarFocus->vt = VT_I4;
  1526. pvarFocus->lVal = 0;
  1527. }
  1528. else
  1529. {
  1530. // NOTE:
  1531. // We differ here in we don't get the foreground thread's focus window. Instead,
  1532. // we just get the current threads focus window
  1533. HWND hwnd = GetFocus();
  1534. if (IsChild(_hwnd, hwnd))
  1535. return(MSAA::GetWindowObject(hwnd, pvarFocus));
  1536. }
  1537. return(S_OK);
  1538. }
  1539. /*
  1540. * CCmbBxWinHost::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
  1541. *
  1542. * @mfunc
  1543. * Retrieves a string containing a localized sentence that describes the object's
  1544. * default action.
  1545. *
  1546. * @rdesc
  1547. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1548. * otherwise.
  1549. */
  1550. STDMETHODIMP CCmbBxWinHost::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
  1551. {
  1552. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accDefaultAction");
  1553. // Validate parameters
  1554. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1555. return(E_INVALIDARG);
  1556. if ((varChild.lVal != INDEX_COMBOBOX_BUTTON)/* || _fHasButton*/)
  1557. return DISP_E_MEMBERNOTFOUND;
  1558. // Default action of button is to press it. If pressed already, pressing
  1559. // it will pop dropdown back up. If not pressed, pressing it will pop
  1560. // dropdown down.
  1561. InitPv(pszDefaultAction);
  1562. if (IsWindowVisible(_hwndList))
  1563. return(MSAA::GetStringResource(STR_DROPDOWN_HIDE, pszDefaultAction));
  1564. else
  1565. return(MSAA::GetStringResource(STR_DROPDOWN_SHOW, pszDefaultAction));
  1566. }
  1567. /*
  1568. * CCmbBxWinHost::accSelect(long flagsSel, VARIANT varChild)
  1569. * @mfunc
  1570. * Modifies the selection or moves the keyboard focus according to the specified
  1571. * flags.
  1572. *
  1573. * @rdesc
  1574. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1575. * otherwise.
  1576. */
  1577. STDMETHODIMP CCmbBxWinHost::accSelect(long flagsSel, VARIANT varChild)
  1578. {
  1579. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::accSelect");
  1580. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX) || !MSAA::ValidateSelFlags(flagsSel))
  1581. return(E_INVALIDARG);
  1582. return(S_FALSE);
  1583. }
  1584. /*
  1585. * CCmbBxWinHost::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
  1586. * @mfunc
  1587. * Retrieves the object's current screen location (if the object was placed on
  1588. * the screen) and optionally, the child element.
  1589. *
  1590. * @rdesc
  1591. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1592. * otherwise.
  1593. */
  1594. STDMETHODIMP CCmbBxWinHost::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
  1595. {
  1596. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::accLocation");
  1597. InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
  1598. // Validate
  1599. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1600. return(E_INVALIDARG);
  1601. RECT rc;
  1602. HWND hwnd = _hwnd;
  1603. switch (varChild.lVal)
  1604. {
  1605. case INDEX_COMBOBOX_BUTTON:
  1606. //if (!m_fHasButton)
  1607. // return(S_FALSE);
  1608. rc = _rcButton;
  1609. *pcxWidth = rc.right - rc.left;
  1610. *pcyHeight = rc.bottom - rc.top;
  1611. ClientToScreen(_hwnd, (LPPOINT)&rc);
  1612. break;
  1613. case INDEX_COMBOBOX_ITEM:
  1614. // Need to verify this is the currently selected item.
  1615. // if no item is selected then pass the rect of the first item in the list
  1616. _plbHost->LbGetItemRect((_plbHost->GetCursor() < 0) ? 0 : _plbHost->GetCursor(), &rc);
  1617. *pcxWidth = rc.right - rc.left;
  1618. *pcyHeight = rc.bottom - rc.top;
  1619. ClientToScreen(_hwndList, (LPPOINT)&rc);
  1620. break;
  1621. case INDEX_COMBOBOX_LIST:
  1622. hwnd = _hwndList;
  1623. // fall through!!!
  1624. case 0: //default window
  1625. GetWindowRect(hwnd, &rc);
  1626. // copy over dimensions
  1627. *pcxWidth = rc.right - rc.left;
  1628. *pcyHeight = rc.bottom - rc.top;
  1629. break;
  1630. default:
  1631. AssertSz(FALSE, "Invalid ChildID for child of combo box" );
  1632. return (S_OK);
  1633. }
  1634. *pxLeft = rc.left;
  1635. *pyTop = rc.top;
  1636. return(S_OK);
  1637. }
  1638. /*
  1639. * CCmbBxWinHost::accNavigate(long dwNav, VARIANT varStart, VARIANT* pvarEnd)
  1640. *
  1641. * @mfunc
  1642. * Retrieves the next or previous sibling or child object in a specified
  1643. * direction.
  1644. *
  1645. * @rdesc
  1646. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1647. * otherwise.
  1648. */
  1649. STDMETHODIMP CCmbBxWinHost::accNavigate(long dwNav, VARIANT varStart, VARIANT* pvarEnd)
  1650. {
  1651. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::accNavigate");
  1652. InitPvar(pvarEnd);
  1653. // Validate parameters
  1654. if (!MSAA::ValidateChild(&varStart, CCHILDREN_COMBOBOX))
  1655. return(E_INVALIDARG);
  1656. long lEnd = 0;
  1657. if (dwNav == NAVDIR_FIRSTCHILD)
  1658. {
  1659. lEnd = INDEX_COMBOBOX_ITEM;
  1660. goto GetTheChild;
  1661. }
  1662. else if (dwNav == NAVDIR_LASTCHILD)
  1663. {
  1664. dwNav = NAVDIR_PREVIOUS;
  1665. varStart.lVal = CCHILDREN_COMBOBOX + 1;
  1666. }
  1667. else if (!varStart.lVal)
  1668. {
  1669. // NOTE:
  1670. // MSAA tries to make a distinction for controls by implementing 2 different types of
  1671. // interfaces for controls.
  1672. // OBJID_WINDOW - will include the windows border along with the client. This control
  1673. // should be perceived from a dialog or some window containers perspective.
  1674. // Where the control is just an abstract entity contained in the window container
  1675. // OBJID_CLIENT - only includes the client area. This interface is only concerned with
  1676. // the control itself and disregards the outside world
  1677. IAccessible* poleacc = NULL;
  1678. HRESULT hr = W32->AccessibleObjectFromWindow(_hwnd, OBJID_WINDOW, IID_IAccessible, (void**)&poleacc);
  1679. if (!SUCCEEDED(hr))
  1680. return(hr);
  1681. // Ask it to navigate
  1682. VARIANT varStart;
  1683. VariantInit(&varStart);
  1684. varStart.vt = VT_I4;
  1685. varStart.lVal = OBJID_CLIENT;
  1686. hr = poleacc->accNavigate(dwNav, varStart, pvarEnd);
  1687. // Release our parent
  1688. poleacc->Release();
  1689. return(hr);
  1690. }
  1691. // Map HWNDID to normal ID. We work with both (it is easier).
  1692. if (IsHWNDID(varStart.lVal))
  1693. {
  1694. HWND hWndTemp = HwndFromHWNDID(varStart.lVal);
  1695. if (hWndTemp == _hwnd)
  1696. varStart.lVal = INDEX_COMBOBOX_ITEM;
  1697. else if (hWndTemp == _hwndList)
  1698. varStart.lVal = INDEX_COMBOBOX_LIST;
  1699. else
  1700. // Don't know what the heck this is
  1701. return(S_FALSE);
  1702. }
  1703. switch (dwNav)
  1704. {
  1705. case NAVDIR_UP:
  1706. if (varStart.lVal == INDEX_COMBOBOX_LIST)
  1707. lEnd = INDEX_COMBOBOX_ITEM;
  1708. break;
  1709. case NAVDIR_DOWN:
  1710. if ((varStart.lVal != INDEX_COMBOBOX_LIST) && _fListVisible)
  1711. lEnd = INDEX_COMBOBOX_LIST;
  1712. break;
  1713. case NAVDIR_LEFT:
  1714. if (varStart.lVal == INDEX_COMBOBOX_BUTTON)
  1715. lEnd = INDEX_COMBOBOX_ITEM;
  1716. break;
  1717. case NAVDIR_RIGHT:
  1718. if ((varStart.lVal == INDEX_COMBOBOX_ITEM)/* && !(cbi.stateButton & STATE_SYSTEM_INVISIBLE)*/)
  1719. lEnd = INDEX_COMBOBOX_BUTTON;
  1720. break;
  1721. case NAVDIR_PREVIOUS:
  1722. lEnd = varStart.lVal - 1;
  1723. if ((lEnd == INDEX_COMBOBOX_LIST) && !_fListVisible)
  1724. --lEnd;
  1725. break;
  1726. case NAVDIR_NEXT:
  1727. lEnd = varStart.lVal + 1;
  1728. if (lEnd > CCHILDREN_COMBOBOX || ((lEnd == INDEX_COMBOBOX_LIST) && !_fListVisible))
  1729. lEnd = 0;
  1730. break;
  1731. }
  1732. GetTheChild:
  1733. if (lEnd)
  1734. {
  1735. // NOTE:
  1736. // MSAA tries to make a distinction for controls by implementing 2 different types of
  1737. // interfaces for controls.
  1738. // OBJID_WINDOW - will include the windows border along with the client. This control
  1739. // should be perceived from a dialog or some window containers perspective.
  1740. // Where the control is just an abstract entity contained in the window container
  1741. // OBJID_CLIENT - only includes the client area. This interface is only concerned with
  1742. // the control itself and disregards the outside world
  1743. if ((lEnd == INDEX_COMBOBOX_ITEM)/* && cbi.hwndItem*/)
  1744. return(MSAA::GetWindowObject(_hwnd, pvarEnd));
  1745. else if ((lEnd == INDEX_COMBOBOX_LIST)/* && cbi.hwndList*/)
  1746. return(MSAA::GetWindowObject(_hwndList, pvarEnd));
  1747. pvarEnd->vt = VT_I4;
  1748. pvarEnd->lVal = lEnd;
  1749. return(S_OK);
  1750. }
  1751. return(S_FALSE);
  1752. }
  1753. /*
  1754. * CCmbBxWinHost::accHitTest(long xLeft, long yTop, VARIANT *pvarEnd)
  1755. *
  1756. * @mfunc
  1757. * Retrieves the child object at a given point on the screen.
  1758. *
  1759. * @rdesc
  1760. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1761. * otherwise.
  1762. */
  1763. STDMETHODIMP CCmbBxWinHost::accHitTest(long xLeft, long yTop, VARIANT *pvarEnd)
  1764. {
  1765. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::accHitTest");
  1766. POINT pt;
  1767. RECT rc;
  1768. InitPvar(pvarEnd);
  1769. pt.x = xLeft;
  1770. pt.y = yTop;
  1771. // Check list first, in case it is a dropdown.
  1772. GetWindowRect(_hwndList, &rc);
  1773. if (_fListVisible && PtInRect(&rc, pt))
  1774. return(MSAA::GetWindowObject(_hwndList, pvarEnd));
  1775. else
  1776. {
  1777. ScreenToClient(_hwnd, &pt);
  1778. GetClientRect(_hwnd, &rc);
  1779. if (PtInRect(&_rcButton, pt))
  1780. {
  1781. pvarEnd->vt = VT_I4;
  1782. pvarEnd->lVal = INDEX_COMBOBOX_BUTTON;
  1783. }
  1784. else
  1785. {
  1786. if (!PtInRect(&rc, pt))
  1787. return(S_FALSE);
  1788. pvarEnd->vt = VT_I4;
  1789. pvarEnd->lVal = 0;
  1790. }
  1791. }
  1792. return(S_OK);
  1793. }
  1794. /*
  1795. * CCmbBxWinHost::accDoDefaultAction(VARIANT varChild)
  1796. *
  1797. * @mfunc
  1798. * Performs the object's default action.
  1799. *
  1800. * @rdesc
  1801. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1802. * otherwise.
  1803. */
  1804. STDMETHODIMP CCmbBxWinHost::accDoDefaultAction(VARIANT varChild)
  1805. {
  1806. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::accDoDefaultAction");
  1807. // Validate
  1808. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1809. return(E_INVALIDARG);
  1810. if ((varChild.lVal == INDEX_COMBOBOX_BUTTON)/* && m_fHasButton*/)
  1811. {
  1812. if (_fListVisible)
  1813. PostMessage(_hwnd, WM_KEYDOWN, VK_RETURN, 0);
  1814. else
  1815. PostMessage(_hwnd, CB_SHOWDROPDOWN, TRUE, 0);
  1816. return(S_OK);
  1817. }
  1818. return DISP_E_MEMBERNOTFOUND;
  1819. }
  1820. /*
  1821. * CCmbBxWinHost::get_accSelection(VARIANT *pvarChildren)
  1822. *
  1823. * @mfunc
  1824. * Retrieves the selected children of this object.
  1825. *
  1826. * @rdesc
  1827. * Returns S_OK if successful or E_INVALIDARG or another standard COM error code
  1828. * otherwise.
  1829. */
  1830. STDMETHODIMP CCmbBxWinHost::get_accSelection(VARIANT *pvarChildren)
  1831. {
  1832. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accSelection");
  1833. InitPvar(pvarChildren);
  1834. return(S_FALSE);
  1835. }
  1836. /*
  1837. * CCmbBxWinHost::get_accParent(IDispatch **ppdispParent)
  1838. *
  1839. * @mfunc
  1840. * Retrieves the IDispatch interface of the current object's parent.
  1841. * Return S_FALSE and set the variable at ppdispParent to NULL.
  1842. *
  1843. * @rdesc
  1844. * HRESULT = S_FALSE.
  1845. */
  1846. STDMETHODIMP CCmbBxWinHost::get_accParent(IDispatch **ppdispParent)
  1847. {
  1848. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accParent");
  1849. InitPv(ppdispParent);
  1850. if (_hwnd)
  1851. {
  1852. HWND hwnd = MSAA::GetAncestor(_hwnd, GA_PARENT);
  1853. if (hwnd)
  1854. return W32->AccessibleObjectFromWindow(hwnd, OBJID_WINDOW,
  1855. IID_IDispatch, (void **)ppdispParent);
  1856. }
  1857. return(S_FALSE);
  1858. }
  1859. /*
  1860. * CCmbBxWinHost::get_accChildCount(long *pcountChildren)
  1861. *
  1862. * @mfunc
  1863. * Retrieves the number of children belonging to the current object.
  1864. *
  1865. * @rdesc
  1866. * HRESULT = S_FALSE.
  1867. */
  1868. STDMETHODIMP CCmbBxWinHost::get_accChildCount(long *pcountChildren)
  1869. {
  1870. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accChildCount");
  1871. if (pcountChildren)
  1872. *pcountChildren = CCHILDREN_COMBOBOX;
  1873. return S_OK;
  1874. }
  1875. /*
  1876. * CCmbBxWinHost::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
  1877. *
  1878. * @mfunc
  1879. * Retrieves the number of children belonging to the current object.
  1880. *
  1881. * @rdesc
  1882. * HRESULT = S_FALSE.
  1883. */
  1884. STDMETHODIMP CCmbBxWinHost::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
  1885. {
  1886. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::get_accChild");
  1887. // Validate
  1888. if (!MSAA::ValidateChild(&varChild, CCHILDREN_COMBOBOX))
  1889. return(E_INVALIDARG);
  1890. InitPv(ppdispChild);
  1891. HWND hwndChild = NULL;
  1892. switch (varChild.lVal)
  1893. {
  1894. case INDEX_COMBOBOX:
  1895. return E_INVALIDARG;
  1896. //case INDEX_COMBOBOX_ITEM:
  1897. // hwndChild = _hwnd;
  1898. // break;
  1899. case INDEX_COMBOBOX_LIST:
  1900. hwndChild = _hwndList;
  1901. break;
  1902. }
  1903. if (!hwndChild)
  1904. return(S_FALSE);
  1905. else
  1906. return(W32->AccessibleObjectFromWindow(hwndChild, OBJID_WINDOW, IID_IDispatch, (void**)ppdispChild));
  1907. }
  1908. //////////////////////// CTxtWinHost IDispatch Methods ///////////////////////////
  1909. // --------------------------------------------------------------------------
  1910. //
  1911. // CTxtWinHost::GetTypeInfoCount()
  1912. //
  1913. // This hands off to our typelib for IAccessible(). Note that
  1914. // we only implement one type of object for now. BOGUS! What about IText?
  1915. //
  1916. // --------------------------------------------------------------------------
  1917. STDMETHODIMP CTxtWinHost::GetTypeInfoCount(UINT * pctInfo)
  1918. {
  1919. HRESULT hr = InitTypeInfo();
  1920. if (SUCCEEDED(hr))
  1921. {
  1922. InitPv(pctInfo);
  1923. *pctInfo = 1;
  1924. }
  1925. return(hr);
  1926. }
  1927. // --------------------------------------------------------------------------
  1928. //
  1929. // CTxtWinHost::GetTypeInfo()
  1930. //
  1931. // --------------------------------------------------------------------------
  1932. STDMETHODIMP CTxtWinHost::GetTypeInfo(UINT itInfo, LCID lcid,
  1933. ITypeInfo ** ppITypeInfo)
  1934. {
  1935. HRESULT hr = InitTypeInfo();
  1936. if (SUCCEEDED(hr))
  1937. {
  1938. if (ppITypeInfo == NULL)
  1939. return(E_POINTER);
  1940. InitPv(ppITypeInfo);
  1941. if (itInfo != 0)
  1942. return(TYPE_E_ELEMENTNOTFOUND);
  1943. _pTypeInfo->AddRef();
  1944. *ppITypeInfo = _pTypeInfo;
  1945. }
  1946. return(hr);
  1947. }
  1948. // --------------------------------------------------------------------------
  1949. //
  1950. // CTxtWinHost::GetIDsOfNames()
  1951. //
  1952. // --------------------------------------------------------------------------
  1953. STDMETHODIMP CTxtWinHost::GetIDsOfNames(REFIID riid,
  1954. OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispID)
  1955. {
  1956. HRESULT hr = InitTypeInfo();
  1957. if (!SUCCEEDED(hr))
  1958. return(hr);
  1959. return(_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispID));
  1960. }
  1961. // --------------------------------------------------------------------------
  1962. //
  1963. // CTxtWinHost::Invoke()
  1964. //
  1965. // --------------------------------------------------------------------------
  1966. STDMETHODIMP CTxtWinHost::Invoke(DISPID dispID, REFIID riid,
  1967. LCID lcid, WORD wFlags, DISPPARAMS * pDispParams,
  1968. VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  1969. {
  1970. HRESULT hr = InitTypeInfo();
  1971. if (!SUCCEEDED(hr))
  1972. return(hr);
  1973. return(_pTypeInfo->Invoke((IAccessible *)this, dispID, wFlags,
  1974. pDispParams, pvarResult, pExcepInfo, puArgErr));
  1975. }
  1976. #endif // NOACCESSIBILITY