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.

1192 lines
32 KiB

  1. //-------------------------------------------------------------------------//
  2. // link.cpp - implementation of CLink
  3. //
  4. // [scotthan] - created 10/7/98
  5. // [markfi] - ported to UxCtrl 3/00
  6. // [t-jklann] - uses markup 7/00
  7. // issues: removed window capture functionality; shouldn't change much
  8. #include <ctlspriv.h>
  9. #include <markup.h>
  10. #include <oleacc.h>
  11. #define DllAddRef()
  12. #define DllRelease()
  13. typedef WCHAR TUCHAR, *PTUCHAR;
  14. #define LINKCOLOR_BKGND COLOR_WINDOW
  15. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags);
  16. BOOL _HandleWM_UPDATEUISTATE(IN WPARAM wParam, IN LPARAM lParam, IN OUT UINT* puFlags);
  17. inline void MakePoint(LPARAM lParam, OUT LPPOINT ppt)
  18. {
  19. POINTS pts = MAKEPOINTS(lParam);
  20. ppt->x = pts.x;
  21. ppt->y = pts.y;
  22. }
  23. STDAPI_(BOOL) IsWM_GETOBJECT(UINT uMsg)
  24. {
  25. return WM_GETOBJECT == uMsg;
  26. }
  27. // common IAccessible implementation.
  28. class CAccessibleBase : public IAccessible, public IOleWindow
  29. {
  30. public:
  31. CAccessibleBase(const HWND& hwnd)
  32. : _cRef(1), _ptiAcc(NULL), _hwnd(hwnd)
  33. {
  34. DllAddRef();
  35. }
  36. virtual ~CAccessibleBase()
  37. {
  38. ATOMICRELEASE(_ptiAcc);
  39. }
  40. // IUnknown
  41. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  42. STDMETHODIMP_(ULONG) AddRef();
  43. STDMETHODIMP_(ULONG) Release();
  44. // IOleWindow
  45. STDMETHODIMP GetWindow(HWND* phwnd);
  46. STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
  47. // IDispatch
  48. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo);
  49. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  50. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames,
  51. LCID lcid, DISPID * rgdispid);
  52. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  53. DISPPARAMS * pdispparams, VARIANT * pvarResult,
  54. EXCEPINFO * pexcepinfo, UINT * puArgErr);
  55. // IAccessible
  56. STDMETHODIMP get_accParent(IDispatch ** ppdispParent);
  57. STDMETHODIMP get_accChildCount(long * pcChildren);
  58. STDMETHODIMP get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild);
  59. STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pbstrValue);
  60. STDMETHODIMP get_accDescription(VARIANT varChild, BSTR * pbstrDescription);
  61. STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
  62. STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
  63. STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pbstrHelp);
  64. STDMETHODIMP get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic);
  65. STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut);
  66. STDMETHODIMP get_accFocus(VARIANT * pvarFocusChild);
  67. STDMETHODIMP get_accSelection(VARIANT * pvarSelectedChildren);
  68. STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction);
  69. STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild);
  70. STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild);
  71. STDMETHODIMP accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt);
  72. STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint);
  73. STDMETHODIMP put_accName(VARIANT varChild, BSTR bstrName);
  74. STDMETHODIMP put_accValue(VARIANT varChild, BSTR bstrValue);
  75. protected:
  76. virtual UINT GetDefaultActionStringID() const = 0;
  77. private:
  78. ULONG _cRef;
  79. ITypeInfo* _ptiAcc;
  80. const HWND& _hwnd;
  81. // Thunked OLEACC defs from winuser.h
  82. #ifndef OBJID_WINDOW
  83. #define OBJID_WINDOW 0x00000000
  84. #endif//OBJID_WINDOW
  85. #ifndef OBJID_TITLEBAR
  86. #define OBJID_TITLEBAR 0xFFFFFFFE
  87. #endif//OBJID_TITLEBAR
  88. #ifndef OBJID_CLIENT
  89. #define OBJID_CLIENT 0xFFFFFFFC
  90. #endif//OBJID_CLIENT
  91. #ifndef CHILDID_SELF
  92. #define CHILDID_SELF 0
  93. #endif//CHILDID_SELF
  94. #define VALIDATEACCCHILD(varChild, idChild, hrFail) \
  95. if (!(VT_I4 == varChild.vt && idChild == varChild.lVal)) {return hrFail;}
  96. } ;
  97. #define TEST_CAPTURE(fTest) ((_fCapture & fTest) != 0)
  98. #define MODIFY_CAPTURE(fSet, fRemove) {if (fSet){_fCapture |= fSet;} if (fRemove){_fCapture &= ~fRemove;}}
  99. #define RESET_CAPTURE() {_fCapture=0;}
  100. class CLink : public CAccessibleBase, public IMarkupCallback
  101. {
  102. public:
  103. CLink();
  104. virtual ~CLink();
  105. // IUnknown
  106. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  107. STDMETHODIMP_(ULONG) AddRef();
  108. STDMETHODIMP_(ULONG) Release();
  109. // IMarkupCallback
  110. STDMETHODIMP GetState(UINT uState);
  111. STDMETHODIMP Notify(int nCode, int iLink);
  112. STDMETHODIMP InvalidateRect(RECT* prc);
  113. STDMETHODIMP OnCustomDraw(DWORD dwDrawStage, HDC hdc, const RECT *prc, DWORD dwItemSpec, UINT uItemState, LRESULT *pdwResult);
  114. // IAccessible specialization
  115. STDMETHODIMP get_accName(VARIANT varChild, BSTR* pbstrName);
  116. STDMETHODIMP accDoDefaultAction(VARIANT varChild);
  117. private:
  118. // CAccessibleBase overrides
  119. UINT GetDefaultActionStringID() const { return IDS_LINKWINDOW_DEFAULTACTION; }
  120. // Utility methods
  121. void Paint(HDC hdc, IN OPTIONAL LPCRECT prcClient = NULL, LPCRECT prcClip = NULL);
  122. // Message handlers
  123. static LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
  124. LRESULT SendNotify(UINT nCode, int iLink, BOOL fGetLinkText) const;
  125. LRESULT GetItem(OUT LITEM* pItem);
  126. LRESULT SetItem(IN LITEM* pItem);
  127. void UpdateTabstop();
  128. // Data
  129. HFONT _hfStatic;
  130. HFONT _hfUnderline;
  131. HWND _hwnd;
  132. UINT _fKeyboardCues;
  133. BOOL _bTransparent;
  134. BOOL _bIgnoreReturn;
  135. BOOL _fEatTabChar;
  136. BOOL _fTabStop;
  137. IControlMarkup* _pMarkup;
  138. UINT _cRef;
  139. HRESULT Initialize();
  140. friend BOOL InitLinkClass(HINSTANCE);
  141. friend BOOL UnInitLinkClass(HINSTANCE);
  142. };
  143. BOOL WINAPI InitLinkClass(HINSTANCE hInstance)
  144. {
  145. WNDCLASSEX wc = {0};
  146. wc.cbSize = sizeof(wc);
  147. wc.style = CS_GLOBALCLASS;
  148. wc.lpfnWndProc = CLink::WndProc;
  149. wc.hInstance = hInstance;
  150. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  151. wc.hbrBackground = (HBRUSH)(LINKCOLOR_BKGND+1);
  152. wc.lpszClassName = WC_LINK;
  153. if (!RegisterClassEx(&wc) && !GetClassInfoEx(hInstance, WC_LINK, &wc))
  154. return FALSE;
  155. return TRUE;
  156. }
  157. BOOL WINAPI UnInitLinkClass(HINSTANCE)
  158. {
  159. return ::UnregisterClass(WC_LINK, HINST_THISDLL);
  160. }
  161. CLink::CLink()
  162. : CAccessibleBase(_hwnd),
  163. _hwnd(NULL),
  164. _fKeyboardCues(0),
  165. _pMarkup(NULL),
  166. _cRef(1)
  167. {
  168. }
  169. CLink::~CLink()
  170. {
  171. if (_pMarkup)
  172. {
  173. _pMarkup->Release();
  174. _pMarkup = NULL;
  175. }
  176. }
  177. HRESULT CLink::Initialize()
  178. {
  179. // NOTE - this is the same code the old linkwindow had to find its parent's font
  180. // I this is bogus - WM_GETFONT is spec'ed as being sent from parent to control, not
  181. // child control to parent... We should probably find a better way of doing this.
  182. _hfStatic = NULL;
  183. _hfUnderline = NULL;
  184. for (HWND hwnd = _hwnd; NULL == _hfStatic && hwnd != NULL; hwnd = GetParent(hwnd))
  185. _hfStatic = (HFONT)::SendMessage( hwnd, WM_GETFONT, 0, 0L );
  186. if (_hfStatic)
  187. {
  188. _hfUnderline = CCCreateUnderlineFont(_hfStatic);
  189. }
  190. // ... get a markup
  191. return Markup_Create(SAFECAST(this, IMarkupCallback*), _hfStatic, _hfUnderline, IID_PPV_ARG(IControlMarkup, &_pMarkup));
  192. }
  193. //-------------------------------------------------------------------------//
  194. // CLink IUnknown implementation override (from CAccessibleBase)
  195. //-------------------------------------------------------------------------//
  196. // override QueryInterface from CAccessibleBase!
  197. STDMETHODIMP CLink::QueryInterface(REFIID riid, void** ppvObj)
  198. {
  199. static const QITAB qit[] =
  200. {
  201. QITABENT(CAccessibleBase, IDispatch),
  202. QITABENT(CAccessibleBase, IAccessible),
  203. QITABENT(CAccessibleBase, IOleWindow),
  204. QITABENT(CLink, IMarkupCallback),
  205. { 0 },
  206. };
  207. return QISearch(this, qit, riid, ppvObj);
  208. }
  209. STDMETHODIMP_(ULONG) CLink::AddRef()
  210. {
  211. return InterlockedIncrement((LONG*)&_cRef);
  212. }
  213. STDMETHODIMP_(ULONG) CLink::Release()
  214. {
  215. ULONG cRef = InterlockedDecrement((LONG*)&_cRef);
  216. if (cRef <= 0)
  217. {
  218. DllRelease();
  219. delete this;
  220. }
  221. return cRef;
  222. }
  223. //-------------------------------------------------------------------------//
  224. // CLink IMarkupCallback implementation
  225. //-------------------------------------------------------------------------//
  226. STDMETHODIMP CLink::GetState(UINT uState)
  227. {
  228. HRESULT hr = E_FAIL;
  229. switch(uState)
  230. {
  231. case MARKUPSTATE_FOCUSED:
  232. hr = (GetFocus()==_hwnd) ? S_OK : S_FALSE;
  233. break;
  234. case MARKUPSTATE_ALLOWMARKUP:
  235. hr = S_OK;
  236. break;
  237. }
  238. return hr;
  239. }
  240. HRESULT CLink::OnCustomDraw(DWORD dwDrawStage, HDC hdc, const RECT *prc, DWORD dwItemSpec, UINT uItemState, LRESULT *pdwResult)
  241. {
  242. NMCUSTOMDRAW nmcd;
  243. ZeroMemory(&nmcd, sizeof(nmcd) );
  244. nmcd.hdr.hwndFrom = _hwnd;
  245. nmcd.hdr.idFrom = (UINT_PTR)GetWindowLong( _hwnd, GWL_ID );
  246. nmcd.hdr.code = NM_CUSTOMDRAW;
  247. nmcd.dwDrawStage = dwDrawStage;
  248. nmcd.hdc = hdc;
  249. if (prc)
  250. CopyRect(&nmcd.rc, prc);
  251. nmcd.dwItemSpec = dwItemSpec;
  252. nmcd.uItemState = uItemState;
  253. LRESULT dwRes = SendMessage(GetParent(_hwnd), WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
  254. if (pdwResult)
  255. *pdwResult = dwRes;
  256. return S_OK;
  257. }
  258. STDMETHODIMP CLink::Notify(int nCode, int iLink)
  259. {
  260. HRESULT hr = E_OUTOFMEMORY;
  261. if (_pMarkup)
  262. {
  263. switch (nCode)
  264. {
  265. case MARKUPMESSAGE_WANTFOCUS:
  266. // Markup wants focus
  267. SetFocus(_hwnd);
  268. break;
  269. case MARKUPMESSAGE_KEYEXECUTE:
  270. SendNotify(NM_RETURN, iLink, TRUE);
  271. break;
  272. case MARKUPMESSAGE_CLICKEXECUTE:
  273. SendNotify(NM_CLICK, iLink, TRUE);
  274. break;
  275. }
  276. }
  277. return hr;
  278. }
  279. STDMETHODIMP CLink::InvalidateRect(RECT* prc)
  280. {
  281. HRESULT hr = E_FAIL;
  282. if (! ::InvalidateRect(_hwnd, prc, TRUE))
  283. hr=S_OK;
  284. return hr;
  285. }
  286. // CLink IAccessible impl
  287. //
  288. // Note: Currently, this IAccessible implementation does not supports only
  289. // single links; multiple links are not supported. All child delegation
  290. // is to/from self. This allows us to blow off the IEnumVARIANT and IDispatch
  291. // implementations.
  292. //
  293. // To shore this up the implementation, we need to implement each link
  294. // as a child IAccessible object and delegate accordingly.
  295. //
  296. STDMETHODIMP CLink::get_accName(VARIANT varChild, BSTR* pbstrName)
  297. {
  298. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  299. if (NULL == pbstrName)
  300. {
  301. return E_POINTER;
  302. }
  303. if (NULL == _pMarkup)
  304. {
  305. return E_OUTOFMEMORY;
  306. }
  307. *pbstrName = NULL;
  308. DWORD dwCch;
  309. HRESULT hr;
  310. if (S_OK == (hr = _pMarkup->GetText(FALSE, NULL, &dwCch)))
  311. {
  312. *pbstrName = SysAllocStringLen(NULL, dwCch);
  313. if (*pbstrName)
  314. hr = _pMarkup->GetText(FALSE, *pbstrName, &dwCch);
  315. else
  316. hr = E_OUTOFMEMORY;
  317. }
  318. return hr;
  319. }
  320. STDMETHODIMP CLink::accDoDefaultAction(VARIANT varChild)
  321. {
  322. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  323. SendNotify(NM_RETURN, NULL, FALSE);
  324. return S_OK;
  325. }
  326. // CLink window implementation
  327. void CLink::Paint(HDC hdcClient, LPCRECT prcClient, LPCRECT prcClip)
  328. {
  329. if (!_pMarkup)
  330. {
  331. return;
  332. }
  333. RECT rcClient;
  334. if (!prcClient)
  335. {
  336. GetClientRect(_hwnd, &rcClient);
  337. prcClient = &rcClient;
  338. }
  339. if (RECTWIDTH(*prcClient) <= 0 ||
  340. RECTHEIGHT(*prcClient) <= 0)
  341. {
  342. return;
  343. }
  344. HDC hdc = hdcClient ? hdcClient : GetDC(_hwnd);
  345. RECT rcDraw = *prcClient; // initialize line rect
  346. HBRUSH hbrOld = NULL;
  347. // initialize background
  348. HBRUSH hbr = (HBRUSH)SendMessage(GetParent(_hwnd), WM_CTLCOLORSTATIC,
  349. (WPARAM)hdc, (LPARAM)_hwnd);
  350. if (hbr)
  351. hbrOld = (HBRUSH)SelectObject(hdc, hbr);
  352. if (_bTransparent)
  353. {
  354. SetBkMode(hdc, TRANSPARENT);
  355. }
  356. else
  357. {
  358. // Clear the background
  359. RECT rcFill = *prcClient;
  360. rcFill.top = rcDraw.top;
  361. FillRect(hdc, &rcFill, hbr);
  362. }
  363. // draw the text
  364. _pMarkup->DrawText(hdc, &rcDraw);
  365. if (hbr)
  366. {
  367. SelectObject(hdc, hbrOld);
  368. }
  369. if (NULL == hdcClient && hdc) // release DC if we acquired it.
  370. {
  371. ReleaseDC(_hwnd, hdc);
  372. }
  373. }
  374. LRESULT CLink::SetItem(IN LITEM* pItem)
  375. {
  376. HRESULT hr = E_FAIL;
  377. if (!_pMarkup)
  378. {
  379. return 0;
  380. }
  381. if (NULL == pItem ||
  382. 0 == (pItem->mask & LIF_ITEMINDEX))
  383. {
  384. return 0; //FEATURE: need to open up search keys to LIF_ITEMID and LIF_URL.
  385. }
  386. if (pItem->iLink>-1)
  387. {
  388. if (pItem->mask & LIF_STATE)
  389. {
  390. // Ask the markup callback to set state
  391. hr = _pMarkup->SetState(pItem->iLink, pItem->stateMask, pItem->state);
  392. // Deal with LIS_ENABLED
  393. if (pItem->stateMask & LIS_ENABLED)
  394. {
  395. if (!IsWindowEnabled(_hwnd))
  396. {
  397. EnableWindow(_hwnd, TRUE);
  398. }
  399. }
  400. }
  401. if (pItem->mask & LIF_ITEMID)
  402. {
  403. hr = _pMarkup->SetLinkText(pItem->iLink, MARKUPLINKTEXT_ID, pItem->szID);
  404. }
  405. if (pItem->mask & LIF_URL)
  406. {
  407. hr = _pMarkup->SetLinkText(pItem->iLink, MARKUPLINKTEXT_URL, pItem->szUrl);
  408. }
  409. }
  410. UpdateTabstop();
  411. return SUCCEEDED(hr);
  412. }
  413. LRESULT CLink::GetItem(OUT LITEM* pItem)
  414. {
  415. HRESULT hr = E_FAIL;
  416. if (!_pMarkup)
  417. {
  418. return 0;
  419. }
  420. if (NULL == pItem || 0 == (pItem->mask & LIF_ITEMINDEX))
  421. {
  422. return 0; //FEATURE: need to open up search keys to LIF_ITEMID and LIF_URL.
  423. }
  424. if (pItem->iLink > -1)
  425. {
  426. if (pItem->mask & LIF_STATE)
  427. {
  428. hr = _pMarkup->GetState(pItem->iLink, pItem->stateMask, &pItem->state);
  429. }
  430. if (pItem->mask & LIF_ITEMID)
  431. {
  432. DWORD dwCch = ARRAYSIZE(pItem->szID);
  433. hr = _pMarkup->GetLinkText(pItem->iLink, MARKUPLINKTEXT_ID, pItem->szID, &dwCch);
  434. }
  435. if (pItem->mask & LIF_URL)
  436. {
  437. DWORD dwCch = ARRAYSIZE(pItem->szUrl);
  438. hr = _pMarkup->GetLinkText(pItem->iLink, MARKUPLINKTEXT_URL, pItem->szUrl, &dwCch);
  439. }
  440. }
  441. return SUCCEEDED(hr);
  442. }
  443. LRESULT CLink::SendNotify(UINT nCode, int iLink, BOOL fGetLinkText) const
  444. {
  445. NMLINK nm;
  446. ZeroMemory(&nm, sizeof(nm));
  447. nm.hdr.hwndFrom = _hwnd;
  448. nm.hdr.idFrom = (UINT_PTR)GetWindowLong(_hwnd, GWL_ID);
  449. nm.hdr.code = nCode;
  450. nm.item.iLink = iLink;
  451. if (fGetLinkText)
  452. {
  453. DWORD dwCch;
  454. dwCch = ARRAYSIZE(nm.item.szID);
  455. _pMarkup->GetLinkText(iLink, MARKUPLINKTEXT_ID, nm.item.szID, &dwCch);
  456. dwCch = ARRAYSIZE(nm.item.szUrl);
  457. _pMarkup->GetLinkText(iLink, MARKUPLINKTEXT_URL, nm.item.szUrl, &dwCch);
  458. }
  459. return SendMessage(GetParent(_hwnd), WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm);
  460. }
  461. void CLink::UpdateTabstop()
  462. {
  463. if (_fTabStop)
  464. SetWindowBits(_hwnd, GWL_STYLE, WS_TABSTOP, (_pMarkup->IsTabbable() == S_OK)?WS_TABSTOP:0);
  465. }
  466. LRESULT WINAPI CLink::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  467. {
  468. LRESULT lRet = 0L;
  469. CLink* pThis = NULL;
  470. if (uMsg == WM_NCCREATE)
  471. {
  472. pThis = new CLink;
  473. if (NULL == pThis)
  474. {
  475. TraceMsg(TF_WARNING, "CLink: Failed to allocate CLink in WM_NCCREATE.");
  476. SetWindowPtr(hwnd, GWLP_USERDATA, 0);
  477. return FALSE;
  478. }
  479. pThis->_hwnd = hwnd;
  480. SetWindowPtr(hwnd, GWLP_USERDATA, pThis);
  481. return TRUE;
  482. }
  483. else
  484. {
  485. pThis = (CLink*)GetWindowPtr(hwnd, GWLP_USERDATA);
  486. }
  487. if (pThis != NULL)
  488. {
  489. ASSERT(pThis->_hwnd == hwnd);
  490. switch(uMsg)
  491. {
  492. case WM_SETFONT:
  493. {
  494. if (pThis->_hfUnderline)
  495. {
  496. DeleteObject(pThis->_hfUnderline);
  497. pThis->_hfUnderline = NULL;
  498. }
  499. pThis->_hfStatic = (HFONT)wParam;
  500. if (pThis->_hfStatic)
  501. pThis->_hfUnderline = CCCreateUnderlineFont(pThis->_hfStatic);
  502. if (pThis->_pMarkup)
  503. pThis->_pMarkup->SetFonts(pThis->_hfStatic, pThis->_hfUnderline);
  504. }
  505. break;
  506. case WM_NCHITTEST:
  507. {
  508. POINT pt;
  509. UINT idLink;
  510. MakePoint(lParam, &pt);
  511. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  512. if (pThis->_pMarkup && pThis->_pMarkup->HitTest(pt, &idLink) == S_OK)
  513. {
  514. return HTCLIENT;
  515. }
  516. return HTTRANSPARENT;
  517. }
  518. case WM_PAINT:
  519. {
  520. PAINTSTRUCT ps;
  521. HDC hdc;
  522. if ((hdc = BeginPaint(pThis->_hwnd, &ps)) != NULL)
  523. {
  524. pThis->Paint(hdc);
  525. EndPaint(pThis->_hwnd, &ps);
  526. }
  527. return lRet;
  528. }
  529. case WM_PRINTCLIENT:
  530. pThis->Paint((HDC)wParam);
  531. return lRet;
  532. case WM_WINDOWPOSCHANGING:
  533. {
  534. WINDOWPOS* pwp = (WINDOWPOS*)lParam;
  535. RECT rc;
  536. GetClientRect(pThis->_hwnd, &rc);
  537. if (0 == (pwp->flags & SWP_NOSIZE) &&
  538. !(pwp->cx == RECTWIDTH(rc) &&
  539. pwp->cy == RECTHEIGHT(rc)))
  540. {
  541. // FEATURE: implement LS_AUTOHEIGHT style by
  542. // calling CalcIdealHeight() to compute the height for
  543. // the given width.
  544. }
  545. break;
  546. }
  547. case WM_SIZE:
  548. {
  549. pThis->Paint(NULL);
  550. break;
  551. }
  552. case WM_CREATE:
  553. {
  554. if ((lRet = DefWindowProc(hwnd, uMsg, wParam, lParam)) == 0)
  555. {
  556. CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
  557. if (FAILED(pThis->Initialize()))
  558. return -1;
  559. _InitializeUISTATE(hwnd, &pThis->_fKeyboardCues);
  560. pThis->_fTabStop = (pcs->style & WS_TABSTOP);
  561. pThis->_pMarkup->SetText(pcs->lpszName);
  562. pThis->UpdateTabstop();
  563. pThis->_bTransparent = (pcs->style & LWS_TRANSPARENT);
  564. pThis->_bIgnoreReturn = (pcs->style & LWS_IGNORERETURN);
  565. }
  566. return lRet;
  567. }
  568. case WM_SETTEXT:
  569. pThis->_pMarkup->SetText((LPCTSTR) lParam);
  570. pThis->UpdateTabstop();
  571. ::InvalidateRect(pThis->_hwnd, NULL, FALSE);
  572. break;
  573. case WM_GETTEXT:
  574. {
  575. DWORD dwCch = (DWORD)wParam;
  576. pThis->_pMarkup->GetText(TRUE, (LPTSTR)lParam, &dwCch);
  577. return lstrlen((LPTSTR)lParam);
  578. }
  579. case WM_GETTEXTLENGTH:
  580. {
  581. DWORD dwCch;
  582. pThis->_pMarkup->GetText(TRUE, NULL, &dwCch);
  583. return dwCch-1; // return length in chars, not including NULL
  584. }
  585. case WM_SETFOCUS:
  586. pThis->_pMarkup->SetFocus();
  587. pThis->SendNotify(NM_SETFOCUS, NULL, NULL);
  588. pThis->InvalidateRect(NULL);
  589. return 0L;
  590. case WM_KILLFOCUS:
  591. pThis->_pMarkup->KillFocus();
  592. return lRet;
  593. case WM_LBUTTONDOWN:
  594. {
  595. POINT pt;
  596. MakePoint(lParam, &pt);
  597. pThis->_pMarkup->OnButtonDown(pt);
  598. break;
  599. }
  600. case WM_LBUTTONUP:
  601. {
  602. POINT pt;
  603. MakePoint(lParam, &pt);
  604. pThis->_pMarkup->OnButtonUp(pt);
  605. break;
  606. }
  607. case WM_MOUSEMOVE:
  608. {
  609. POINT pt;
  610. UINT idLink;
  611. MakePoint(lParam, &pt);
  612. if (pThis->_pMarkup->HitTest(pt, &idLink) == S_OK)
  613. {
  614. pThis->_pMarkup->SetLinkCursor();
  615. }
  616. break;
  617. }
  618. case LM_HITTEST: // wParam: n/a, lparam: PLITEM, ret: BOOL
  619. {
  620. LHITTESTINFO* phti = (LHITTESTINFO*)lParam;
  621. if (phti)
  622. {
  623. if (SUCCEEDED(pThis->_pMarkup->HitTest(phti->pt, (UINT*)&phti->item.iLink)))
  624. {
  625. DWORD cch = ARRAYSIZE(phti->item.szID);
  626. return (S_OK == pThis->_pMarkup->GetLinkText(phti->item.iLink, MARKUPLINKTEXT_ID, phti->item.szID, &cch));
  627. }
  628. }
  629. return lRet;
  630. }
  631. case LM_SETITEM:
  632. return pThis->SetItem((LITEM*)lParam);
  633. case LM_GETITEM:
  634. return pThis->GetItem((LITEM*)lParam);
  635. case LM_GETIDEALHEIGHT: // wParam: cx, lparam: n/a, ret: cy
  636. {
  637. HDC hdc = GetDC(hwnd);
  638. if (hdc)
  639. {
  640. RECT rc;
  641. SetRect(&rc, 0, 0, (int)wParam, 0);
  642. pThis->_pMarkup->CalcIdealSize(hdc, MARKUPSIZE_CALCHEIGHT, &rc);
  643. ReleaseDC(hwnd, hdc);
  644. return rc.bottom;
  645. }
  646. return -1;
  647. }
  648. case WM_NCDESTROY:
  649. {
  650. lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
  651. SetWindowPtr(hwnd, GWLP_USERDATA, 0);
  652. if (pThis->_pMarkup)
  653. pThis->_pMarkup->SetCallback(NULL);
  654. if (pThis->_hfUnderline)
  655. DeleteObject(pThis->_hfUnderline);
  656. pThis->_hwnd = NULL;
  657. pThis->Release();
  658. return lRet;
  659. }
  660. case WM_GETDLGCODE:
  661. {
  662. MSG* pmsg;
  663. lRet = DLGC_STATIC;
  664. if ((pmsg = (MSG*)lParam))
  665. {
  666. if ((WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message))
  667. {
  668. switch(pmsg->wParam)
  669. {
  670. case VK_TAB:
  671. if (pThis->_pMarkup->IsTabbable() == S_OK)
  672. {
  673. lRet |= DLGC_WANTTAB;
  674. pThis->_fEatTabChar = TRUE;
  675. }
  676. break;
  677. case VK_RETURN:
  678. if (pThis->_bIgnoreReturn)
  679. break;
  680. // deliberate drop through..
  681. case VK_SPACE:
  682. lRet |= DLGC_WANTALLKEYS;
  683. break;
  684. }
  685. }
  686. else if (WM_CHAR == pmsg->message)
  687. {
  688. if (VK_RETURN == pmsg->wParam)
  689. {
  690. // Eat VK_RETURN WM_CHARs; we don't want
  691. // Dialog manager to beep when IsDialogMessage gets it.
  692. lRet |= DLGC_WANTMESSAGE;
  693. }
  694. else if (VK_TAB == pmsg->wParam &&
  695. pThis->_fEatTabChar)
  696. {
  697. pThis->_fEatTabChar = FALSE;
  698. lRet |= DLGC_WANTTAB;
  699. }
  700. }
  701. }
  702. return lRet;
  703. }
  704. case WM_KEYDOWN:
  705. pThis->_pMarkup->OnKeyDown((UINT)wParam);
  706. case WM_KEYUP:
  707. case WM_CHAR:
  708. return lRet;
  709. case WM_UPDATEUISTATE:
  710. if (_HandleWM_UPDATEUISTATE(wParam, lParam, &pThis->_fKeyboardCues))
  711. {
  712. RedrawWindow(hwnd, NULL, NULL,
  713. RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
  714. }
  715. break;
  716. default:
  717. // oleacc defs thunked for WINVER < 0x0500
  718. if (IsWM_GETOBJECT(uMsg) && OBJID_CLIENT == lParam)
  719. {
  720. return LresultFromObject(IID_IAccessible, wParam, SAFECAST(pThis, IAccessible*));
  721. }
  722. break;
  723. }
  724. }
  725. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  726. }
  727. // CAccessibleBase IUnknown impl
  728. STDMETHODIMP CAccessibleBase::QueryInterface(REFIID riid, void** ppvObj)
  729. {
  730. static const QITAB qit[] =
  731. {
  732. QITABENT(CAccessibleBase, IDispatch),
  733. QITABENT(CAccessibleBase, IAccessible),
  734. QITABENT(CAccessibleBase, IOleWindow),
  735. { 0 },
  736. };
  737. return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
  738. }
  739. STDMETHODIMP_(ULONG) CAccessibleBase::AddRef()
  740. {
  741. return InterlockedIncrement((LONG*)&_cRef);
  742. }
  743. STDMETHODIMP_(ULONG) CAccessibleBase::Release()
  744. {
  745. ULONG cRef = InterlockedDecrement((LONG*)&_cRef);
  746. if (cRef <= 0)
  747. {
  748. DllRelease();
  749. delete this;
  750. }
  751. return cRef;
  752. }
  753. // IOleWindow impl
  754. STDMETHODIMP CAccessibleBase::GetWindow(HWND* phwnd)
  755. {
  756. *phwnd = _hwnd;
  757. return IsWindow(_hwnd) ? S_OK : S_FALSE;
  758. }
  759. //-------------------------------------------------------------------------//
  760. // CAccessibleBase IDispatch impl
  761. //-------------------------------------------------------------------------//
  762. static BOOL _accLoadTypeInfo(ITypeInfo** ppti)
  763. {
  764. ITypeLib* ptl;
  765. HRESULT hr = LoadTypeLib(L"oleacc.dll", &ptl);
  766. if (SUCCEEDED(hr))
  767. {
  768. hr = ptl->GetTypeInfoOfGuid(IID_IAccessible, ppti);
  769. ATOMICRELEASE(ptl);
  770. }
  771. return SUCCEEDED(hr);
  772. }
  773. STDMETHODIMP CAccessibleBase::GetTypeInfoCount(UINT * pctinfo)
  774. {
  775. *pctinfo = 1;
  776. return S_OK;
  777. }
  778. STDMETHODIMP CAccessibleBase::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  779. {
  780. HRESULT hr = E_FAIL;
  781. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  782. {
  783. return hr;
  784. }
  785. *pptinfo = _ptiAcc;
  786. (*pptinfo)->AddRef();
  787. return S_OK;
  788. }
  789. STDMETHODIMP CAccessibleBase::GetIDsOfNames(
  790. REFIID riid,
  791. OLECHAR** rgszNames,
  792. UINT cNames,
  793. LCID lcid, DISPID * rgdispid)
  794. {
  795. HRESULT hr = E_FAIL;
  796. if (IID_NULL != riid && IID_IAccessible != riid)
  797. {
  798. return DISP_E_UNKNOWNINTERFACE;
  799. }
  800. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  801. {
  802. return hr;
  803. }
  804. return _ptiAcc->GetIDsOfNames(rgszNames, cNames, rgdispid);
  805. }
  806. STDMETHODIMP CAccessibleBase::Invoke(
  807. DISPID dispidMember,
  808. REFIID riid,
  809. LCID lcid,
  810. WORD wFlags,
  811. DISPPARAMS * pdispparams,
  812. VARIANT * pvarResult,
  813. EXCEPINFO * pexcepinfo,
  814. UINT * puArgErr)
  815. {
  816. HRESULT hr = E_FAIL;
  817. if (IID_NULL != riid && IID_IAccessible != riid)
  818. {
  819. return DISP_E_UNKNOWNINTERFACE;
  820. }
  821. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  822. {
  823. return hr;
  824. }
  825. return _ptiAcc->Invoke(this, dispidMember, wFlags, pdispparams,
  826. pvarResult, pexcepinfo, puArgErr);
  827. }
  828. STDMETHODIMP CAccessibleBase::get_accParent(IDispatch ** ppdispParent)
  829. {
  830. *ppdispParent = NULL;
  831. if (IsWindow(_hwnd))
  832. {
  833. return AccessibleObjectFromWindow(_hwnd, OBJID_WINDOW,
  834. IID_IDispatch, (void **)ppdispParent);
  835. }
  836. return S_FALSE;
  837. }
  838. STDMETHODIMP CAccessibleBase::get_accChildCount(long * pcChildren)
  839. {
  840. *pcChildren = 0;
  841. return S_OK;
  842. }
  843. STDMETHODIMP CAccessibleBase::get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild)
  844. {
  845. *ppdispChild = NULL;
  846. return S_FALSE;
  847. }
  848. STDMETHODIMP CAccessibleBase::get_accValue(VARIANT varChild, BSTR* pbstrValue)
  849. {
  850. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  851. *pbstrValue = NULL;
  852. return S_FALSE;
  853. }
  854. STDMETHODIMP CAccessibleBase::get_accDescription(VARIANT varChild, BSTR * pbstrDescription)
  855. {
  856. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  857. *pbstrDescription = NULL;
  858. return S_FALSE;
  859. }
  860. STDMETHODIMP CAccessibleBase::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  861. {
  862. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  863. pvarRole->vt = VT_I4;
  864. pvarRole->lVal = ROLE_SYSTEM_LINK;
  865. return S_OK;
  866. }
  867. STDMETHODIMP CAccessibleBase::get_accState(VARIANT varChild, VARIANT *pvarState)
  868. {
  869. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  870. pvarState->vt = VT_I4;
  871. pvarState->lVal = STATE_SYSTEM_DEFAULT ;
  872. if (GetFocus() == _hwnd)
  873. {
  874. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  875. }
  876. else if (IsWindowEnabled(_hwnd))
  877. {
  878. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  879. }
  880. if (!IsWindowVisible(_hwnd))
  881. {
  882. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  883. }
  884. return S_OK;
  885. }
  886. STDMETHODIMP CAccessibleBase::get_accHelp(VARIANT varChild, BSTR* pbstrHelp)
  887. {
  888. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  889. *pbstrHelp = NULL;
  890. return S_FALSE;
  891. }
  892. STDMETHODIMP CAccessibleBase::get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic)
  893. {
  894. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  895. *pbstrHelpFile = NULL;
  896. *pidTopic = -1;
  897. return S_FALSE;
  898. }
  899. STDMETHODIMP CAccessibleBase::get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut)
  900. {
  901. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  902. *pbstrKeyboardShortcut = NULL;
  903. return S_FALSE;
  904. }
  905. STDMETHODIMP CAccessibleBase::get_accFocus(VARIANT * pvarFocusChild)
  906. {
  907. HWND hwndFocus;
  908. if ((hwndFocus = GetFocus()) == _hwnd || IsChild(_hwnd, hwndFocus))
  909. {
  910. pvarFocusChild->vt = VT_I4;
  911. pvarFocusChild->lVal = CHILDID_SELF;
  912. return S_OK;
  913. }
  914. return S_FALSE;
  915. }
  916. STDMETHODIMP CAccessibleBase::get_accSelection(VARIANT * pvarSelectedChildren)
  917. {
  918. return get_accFocus(pvarSelectedChildren); // implemented same as focus.
  919. }
  920. STDMETHODIMP CAccessibleBase::get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction)
  921. {
  922. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  923. WCHAR wsz[128];
  924. if (LoadStringW(HINST_THISDLL, GetDefaultActionStringID(), wsz, ARRAYSIZE(wsz)))
  925. {
  926. if (NULL == (*pbstrDefaultAction = SysAllocString(wsz)))
  927. {
  928. return E_OUTOFMEMORY;
  929. }
  930. return S_OK;
  931. }
  932. return E_FAIL;
  933. }
  934. STDMETHODIMP CAccessibleBase::accSelect(long flagsSelect, VARIANT varChild)
  935. {
  936. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  937. if (flagsSelect & SELFLAG_TAKEFOCUS)
  938. {
  939. SetFocus(_hwnd);
  940. return S_OK;
  941. }
  942. return S_FALSE;
  943. }
  944. STDMETHODIMP CAccessibleBase::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  945. {
  946. RECT rc;
  947. GetWindowRect(_hwnd, &rc);
  948. *pxLeft = rc.left;
  949. *pyTop = rc.top;
  950. *pcxWidth = RECTWIDTH(rc);
  951. *pcyHeight = RECTHEIGHT(rc);
  952. varChild.vt = VT_I4;
  953. varChild.lVal = CHILDID_SELF;
  954. return S_OK;
  955. }
  956. STDMETHODIMP CAccessibleBase::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  957. {
  958. return S_FALSE;
  959. }
  960. STDMETHODIMP CAccessibleBase::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  961. {
  962. pvarChildAtPoint->vt = VT_I4;
  963. pvarChildAtPoint->lVal = CHILDID_SELF;
  964. return S_OK;
  965. }
  966. STDMETHODIMP CAccessibleBase::put_accName(VARIANT varChild, BSTR bstrName)
  967. {
  968. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  969. return S_FALSE;
  970. }
  971. STDMETHODIMP CAccessibleBase::put_accValue(VARIANT varChild, BSTR bstrValue)
  972. {
  973. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  974. return S_FALSE;
  975. }
  976. //-------------------------------------------------------------------------//
  977. // KEYBOARDCUES helpes
  978. BOOL _HandleWM_UPDATEUISTATE(
  979. IN WPARAM wParam,
  980. IN LPARAM lParam,
  981. IN OUT UINT* puFlags)
  982. {
  983. UINT uFlags = *puFlags;
  984. switch(LOWORD(wParam))
  985. {
  986. case UIS_CLEAR:
  987. *puFlags &= ~(HIWORD(wParam));
  988. break;
  989. case UIS_SET:
  990. *puFlags |= HIWORD(wParam);
  991. break;
  992. }
  993. return uFlags != *puFlags;
  994. }
  995. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags)
  996. {
  997. HWND hwndParent = GetParent(hwnd);
  998. *puFlags = (UINT)SendMessage(hwndParent, WM_QUERYUISTATE, 0, 0L);
  999. }