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.

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