Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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