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.

1572 lines
44 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include <oleacc.h>
  4. #ifndef POINTSPERRECT
  5. #define POINTSPERRECT (sizeof(RECT)/sizeof(POINT))
  6. #endif
  7. #define TESTKEYSTATE(vk) ((GetKeyState(vk) & 0x8000)!=0)
  8. #define LINKCOLOR_BKGND COLOR_WINDOW
  9. #define LINKCOLOR_ENABLED GetSysColor(COLOR_HOTLIGHT)
  10. #define LINKCOLOR_DISABLED GetSysColor(COLOR_GRAYTEXT)
  11. #define CF_SETCAPTURE 0x0001
  12. #define CF_SETFOCUS 0x0002
  13. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags);
  14. BOOL _HandleWM_UPDATEUISTATE(IN WPARAM wParam, IN LPARAM lParam, IN OUT UINT* puFlags);
  15. // common IAccessible implementation.
  16. class CAccessibleBase : public IAccessible, public IOleWindow
  17. {
  18. public:
  19. CAccessibleBase(const HWND& hwnd)
  20. : _cRef(1), _ptiAcc(NULL), _hwnd(hwnd)
  21. {
  22. DllAddRef();
  23. }
  24. virtual ~CAccessibleBase()
  25. {
  26. DllRelease();
  27. ATOMICRELEASE(_ptiAcc);
  28. }
  29. // IUnknown
  30. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  31. STDMETHODIMP_(ULONG) AddRef();
  32. STDMETHODIMP_(ULONG) Release();
  33. // IOleWindow
  34. STDMETHODIMP GetWindow(HWND* phwnd);
  35. STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
  36. // IDispatch
  37. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo);
  38. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  39. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames,
  40. LCID lcid, DISPID * rgdispid);
  41. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  42. DISPPARAMS * pdispparams, VARIANT * pvarResult,
  43. EXCEPINFO * pexcepinfo, UINT * puArgErr);
  44. // IAccessible
  45. STDMETHODIMP get_accParent(IDispatch ** ppdispParent);
  46. STDMETHODIMP get_accChildCount(long * pcChildren);
  47. STDMETHODIMP get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild);
  48. STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pbstrValue);
  49. STDMETHODIMP get_accDescription(VARIANT varChild, BSTR * pbstrDescription);
  50. STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
  51. STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
  52. STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pbstrHelp);
  53. STDMETHODIMP get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic);
  54. STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut);
  55. STDMETHODIMP get_accFocus(VARIANT FAR * pvarFocusChild);
  56. STDMETHODIMP get_accSelection(VARIANT FAR * pvarSelectedChildren);
  57. STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction);
  58. STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild);
  59. STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild);
  60. STDMETHODIMP accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt);
  61. STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint);
  62. STDMETHODIMP put_accName(VARIANT varChild, BSTR bstrName);
  63. STDMETHODIMP put_accValue(VARIANT varChild, BSTR bstrValue);
  64. protected:
  65. virtual UINT GetDefaultActionStringID() const = 0;
  66. private:
  67. LONG _cRef;
  68. ITypeInfo* _ptiAcc;
  69. const HWND& _hwnd;
  70. #define VALIDATEACCCHILD(varChild, idChild, hrFail) \
  71. if (!(VT_I4 == varChild.vt && idChild == varChild.lVal)) {return hrFail;}
  72. };
  73. #define TEST_CAPTURE(fTest) ((_fCapture & fTest) != 0)
  74. #define MODIFY_CAPTURE(fSet, fRemove) {if (fSet){_fCapture |= fSet;} if (fRemove){_fCapture &= ~fRemove;}}
  75. #define RESET_CAPTURE() {_fCapture=0;}
  76. // this API for compat with old clients of the shell32 link window. that is now
  77. // in comctl32.dll
  78. BOOL WINAPI LinkWindow_RegisterClass()
  79. {
  80. // get the comctl32 linkwindow, and point the old classname at it
  81. INITCOMMONCONTROLSEX iccs = {sizeof(iccs), ICC_LINK_CLASS};
  82. InitCommonControlsEx(&iccs);
  83. WNDCLASS wc;
  84. ULONG_PTR dwCookie = 0;
  85. SHActivateContext(&dwCookie);
  86. BOOL bRet = GetClassInfo(NULL, WC_LINK, &wc);
  87. SHDeactivateContext(dwCookie);
  88. if (bRet)
  89. {
  90. wc.lpszClassName = TEXT("Link Window"); // old class name for old clients
  91. RegisterClass(&wc);
  92. }
  93. return bRet;
  94. }
  95. BOOL WINAPI LinkWindow_UnregisterClass(HINSTANCE)
  96. {
  97. return TRUE;
  98. }
  99. #define GROUPBTN_BKCOLOR COLOR_WINDOW
  100. #define CAPTION_VPADDING 3
  101. #define CAPTION_HPADDING 2
  102. #define GBM_SENDNOTIFY (GBM_LAST + 1)
  103. // class CGroupBtn
  104. class CGroupBtn : public CAccessibleBase
  105. { // all members private:
  106. CGroupBtn(HWND hwnd);
  107. ~CGroupBtn();
  108. // IAccessible specialization
  109. STDMETHODIMP get_accName(VARIANT varChild, BSTR* pbstrName);
  110. STDMETHODIMP accDoDefaultAction(VARIANT varChild);
  111. // CAccessibleBase overrides
  112. UINT GetDefaultActionStringID() const { return IDS_GROUPBTN_DEFAULTACTION; }
  113. // window procedures
  114. static LRESULT WINAPI s_GroupBtnWndProc(HWND, UINT, WPARAM, LPARAM);
  115. LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
  116. static LRESULT WINAPI s_BuddyProc(HWND, UINT, WPARAM, LPARAM);
  117. // message handlers
  118. void NcCreate(LPCREATESTRUCT lpcs);
  119. LRESULT NcCalcSize(BOOL, LPNCCALCSIZE_PARAMS);
  120. void NcPaint(HRGN);
  121. LRESULT NcMouseMove(WPARAM, LONG, LONG);
  122. LRESULT NcHitTest(LONG, LONG);
  123. LRESULT NcButtonDown(UINT nMsg, WPARAM nHittest, const POINTS& pts);
  124. LRESULT NcDblClick(UINT nMsg, WPARAM nHittest, LPARAM lParam);
  125. LRESULT ButtonUp(UINT nMsg, WPARAM nHittest, const POINTS& pts);
  126. void OnCaptureLost(HWND hwndNew) {RESET_CAPTURE();}
  127. LRESULT WindowPosChanging(LPWINDOWPOS);
  128. LRESULT OnSize(WPARAM, LONG, LONG);
  129. BOOL SetPlacement(PGBPLACEMENT);
  130. BOOL SetBuddy(HWND, ULONG);
  131. void SetText(LPCTSTR);
  132. int GetText(LPTSTR, int);
  133. int GetTextW(LPWSTR, int);
  134. int GetTextLength();
  135. void SetFont(HFONT);
  136. HFONT GetFont();
  137. // utility methods
  138. static void _MapWindowRect(HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow);
  139. void _MapWindowRect(HWND hwndRelative, OUT LPRECT prcWindow);
  140. HCURSOR GetHandCursor();
  141. void CalcCaptionSize();
  142. BOOL CalcClientRect(IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient);
  143. BOOL CalcWindowSizeForClient(IN OPTIONAL LPCRECT prcClient,
  144. IN OPTIONAL LPCRECT prcWindow,
  145. IN LPCRECT prcNewClient,
  146. OUT LPSIZE psizeWindow);
  147. void DoLayout(BOOL bNewBuddy = FALSE);
  148. LONG EnableNotifications(BOOL bEnable);
  149. LRESULT SendNotify(int nCode, IN OPTIONAL NMHDR* pnmh = NULL);
  150. // instance and static data
  151. HWND _hwnd;
  152. HWND _hwndBuddy;
  153. WNDPROC _pfnBuddy;
  154. ULONG _dwBuddyFlags;
  155. SIZE _sizeBuddyMargin;
  156. HFONT _hf;
  157. static ATOM _atom;
  158. LPTSTR _pszCaption;
  159. SIZE _sizeCaption;
  160. int _yDrop;
  161. BOOL _fDropped : 1,
  162. _fInLayout : 1;
  163. UINT _fCapture;
  164. UINT _fKeyboardCues;
  165. HCURSOR _hcurHand;
  166. LONG _cNotifyLocks;
  167. friend ATOM GroupButton_RegisterClass();
  168. friend HWND CreateGroupBtn(DWORD, LPCTSTR, DWORD,
  169. int x, int y, HWND hwndParent, UINT nID);
  170. };
  171. ATOM WINAPI GroupButton_RegisterClass()
  172. {
  173. WNDCLASSEX wc = {0};
  174. wc.cbSize = sizeof(wc);
  175. wc.style = CS_GLOBALCLASS;
  176. wc.lpfnWndProc = CGroupBtn::s_GroupBtnWndProc;
  177. wc.hInstance = HINST_THISDLL;
  178. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  179. wc.hbrBackground = (HBRUSH)(GROUPBTN_BKCOLOR+1);
  180. wc.lpszClassName = GROUPBUTTON_CLASS;
  181. RegisterClassEx(&wc);
  182. return (ATOM)TRUE;
  183. }
  184. CGroupBtn::CGroupBtn(HWND hwnd)
  185. : CAccessibleBase(_hwnd),
  186. _hwnd(hwnd),
  187. _hwndBuddy(NULL),
  188. _pfnBuddy(NULL),
  189. _dwBuddyFlags(GBBF_HRESIZE|GBBF_VRESIZE),
  190. _fInLayout(FALSE),
  191. _hf(NULL),
  192. _pszCaption(NULL),
  193. _fDropped(TRUE),
  194. _fKeyboardCues(0),
  195. _yDrop(0),
  196. _fCapture(0),
  197. _hcurHand(NULL),
  198. _cNotifyLocks(0)
  199. {
  200. _sizeCaption.cx = _sizeCaption.cy = 0;
  201. _sizeBuddyMargin.cx = _sizeBuddyMargin.cy = 0;
  202. }
  203. ATOM CGroupBtn::_atom = 0;
  204. CGroupBtn::~CGroupBtn()
  205. {
  206. SetFont(NULL);
  207. SetText(NULL);
  208. }
  209. // CGroupBtn IAccessible impl
  210. STDMETHODIMP CGroupBtn::get_accName(VARIANT varChild, BSTR* pbstrName)
  211. {
  212. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  213. if (NULL == pbstrName)
  214. return E_POINTER;
  215. *pbstrName = 0;
  216. int cch = GetTextLength();
  217. if ((*pbstrName = SysAllocStringLen(NULL, cch + 1)) != NULL)
  218. {
  219. GetTextW(*pbstrName, cch + 1);
  220. return S_OK;
  221. }
  222. return E_OUTOFMEMORY;
  223. }
  224. STDMETHODIMP CGroupBtn::accDoDefaultAction(VARIANT varChild)
  225. {
  226. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  227. SendNotify(NM_RETURN);
  228. return S_OK;
  229. }
  230. // CGroupBtn window impl
  231. // WM_SETTEXT handler
  232. void CGroupBtn::SetText(LPCTSTR pszText)
  233. {
  234. if (_pszCaption)
  235. {
  236. if (pszText && 0==lstrcmp(_pszCaption, pszText))
  237. return;
  238. delete [] _pszCaption;
  239. _pszCaption = NULL;
  240. }
  241. if (pszText && *pszText)
  242. {
  243. if ((_pszCaption = new TCHAR[lstrlen(pszText)+1]) != NULL)
  244. lstrcpy(_pszCaption, pszText);
  245. }
  246. if (IsWindow(_hwnd))
  247. CalcCaptionSize();
  248. }
  249. // WM_GETTEXT handler
  250. int CGroupBtn::GetText(LPTSTR pszText, int cchText)
  251. {
  252. int cch = 0;
  253. if (pszText && cchText > 0)
  254. {
  255. *pszText = 0;
  256. if (_pszCaption && lstrcpyn(pszText, _pszCaption, cchText))
  257. cch = min(lstrlen(_pszCaption), cchText);
  258. }
  259. return cch;
  260. }
  261. int CGroupBtn::GetTextW(LPWSTR pwszText, int cchText)
  262. {
  263. #ifdef UNICODE
  264. return GetText(pwszText, cchText);
  265. #else //UNICODE
  266. int cchRet = 0;
  267. LPSTR pszText = new CHAR[cchText];
  268. if (pszText)
  269. {
  270. cchRet = GetText(pszText, cchText);
  271. if (cchRet)
  272. {
  273. SHAnsiToUnicode(pszText, pwszText, cchText);
  274. }
  275. delete [] pszText;
  276. }
  277. return cchRet;
  278. #endif //UNICODE
  279. }
  280. // WM_GETTEXTLENGTH handler
  281. int CGroupBtn::GetTextLength()
  282. {
  283. return (_pszCaption && *_pszCaption) ? lstrlen(_pszCaption) : 0 ;
  284. }
  285. // WM_SETFONT handler
  286. void CGroupBtn::SetFont(HFONT hf)
  287. {
  288. if (_hf)
  289. {
  290. DeleteObject(_hf);
  291. _hf = NULL;
  292. }
  293. _hf = hf;
  294. }
  295. // WM_GETFONT handler
  296. HFONT CGroupBtn::GetFont()
  297. {
  298. if (_hf == NULL)
  299. {
  300. // if we don't have a font, use the parent's font
  301. HFONT hfParent = (HFONT)SendMessage(GetParent(_hwnd), WM_GETFONT, 0, 0);
  302. if (hfParent)
  303. {
  304. LOGFONT lf;
  305. if (GetObject(hfParent, sizeof(LOGFONT), &lf) >0)
  306. _hf = CreateFontIndirect(&lf);
  307. }
  308. }
  309. return _hf;
  310. }
  311. // Hand cursor load
  312. HCURSOR CGroupBtn::GetHandCursor()
  313. {
  314. if (!_hcurHand)
  315. _hcurHand = LoadCursor(NULL, IDC_HAND);
  316. return _hcurHand;
  317. }
  318. // Retrieves the window rect in relative coords.
  319. void CGroupBtn::_MapWindowRect(HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow)
  320. {
  321. ASSERT(IsWindow(hwnd));
  322. GetWindowRect(hwnd, prcWindow);
  323. MapWindowPoints(HWND_DESKTOP, hwndRelative, (LPPOINT)prcWindow, 2);
  324. }
  325. // Retrieves the window rect in relative coords.
  326. inline void CGroupBtn::_MapWindowRect(HWND hwndRelative, OUT LPRECT prcWindow)
  327. {
  328. _MapWindowRect(_hwnd, hwndRelative, prcWindow);
  329. }
  330. // Caches the size of the caption 'bar'.
  331. void CGroupBtn::CalcCaptionSize()
  332. {
  333. SIZE sizeCaption = {0,0};
  334. LPCTSTR pszCaption = (_pszCaption && *_pszCaption) ? _pszCaption : TEXT("|");
  335. HDC hdc;
  336. // compute caption size based on window text:
  337. if ((hdc = GetDC(_hwnd)))
  338. {
  339. HFONT hf = GetFont(),
  340. hfPrev = (HFONT)SelectObject(hdc, hf);
  341. if (GetTextExtentPoint32(hdc, pszCaption, lstrlen(pszCaption),
  342. &sizeCaption))
  343. sizeCaption.cy += CAPTION_VPADDING; // add some vertical padding
  344. SelectObject(hdc, hfPrev);
  345. ReleaseDC(_hwnd, hdc);
  346. }
  347. _sizeCaption = sizeCaption;
  348. }
  349. // Computes the size and position of the client area
  350. BOOL CGroupBtn::CalcClientRect(IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient)
  351. {
  352. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  353. RECT rcWindow;
  354. if (!prcWindow)
  355. {
  356. // Get parent-relative coords
  357. _MapWindowRect(GetParent(_hwnd), &rcWindow);
  358. prcWindow = &rcWindow;
  359. }
  360. *prcClient = *prcWindow;
  361. // compute client rectangle:
  362. // allow for border
  363. if (dwStyle & WS_BORDER)
  364. InflateRect(prcClient, -1, -1);
  365. // allow for caption 'bar'
  366. prcClient->top += _sizeCaption.cy;
  367. // Normalize for NULL rect.
  368. if (RECTWIDTH(*prcWindow) <=0)
  369. prcClient->left = prcClient->right = prcWindow->left;
  370. if (RECTHEIGHT(*prcWindow) <=0)
  371. prcClient->bottom = prcClient->top = prcWindow->top;
  372. return TRUE;
  373. }
  374. BOOL CGroupBtn::CalcWindowSizeForClient(
  375. IN OPTIONAL LPCRECT prcClient,
  376. IN OPTIONAL LPCRECT prcWindow,
  377. IN LPCRECT prcNewClient,
  378. OUT LPSIZE psizeWindow)
  379. {
  380. if (!(prcNewClient && psizeWindow))
  381. {
  382. ASSERT(FALSE);
  383. return FALSE;
  384. }
  385. RECT rcWindow, rcClient;
  386. if (NULL == prcWindow)
  387. {
  388. GetWindowRect(_hwnd, &rcWindow);
  389. prcWindow = &rcWindow;
  390. }
  391. if (NULL == prcClient)
  392. {
  393. GetClientRect(_hwnd, &rcClient);
  394. prcClient = &rcClient;
  395. }
  396. SIZE sizeDelta;
  397. sizeDelta.cx = RECTWIDTH(*prcWindow) - RECTWIDTH(*prcClient);
  398. sizeDelta.cy = RECTHEIGHT(*prcWindow) - RECTHEIGHT(*prcClient);
  399. psizeWindow->cx = RECTWIDTH(*prcNewClient) + sizeDelta.cx;
  400. psizeWindow->cy = RECTHEIGHT(*prcNewClient) + sizeDelta.cy;
  401. return TRUE;
  402. }
  403. // WM_WINDOWPOSCHANGING handler
  404. LRESULT CGroupBtn::WindowPosChanging(LPWINDOWPOS pwp)
  405. {
  406. if (pwp->flags & SWP_NOSIZE)
  407. return DefWindowProc(_hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pwp);
  408. // disallow sizing in buddy slave dimension(s).
  409. if (IsWindow(_hwndBuddy) && _dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE) && !_fInLayout)
  410. {
  411. RECT rcWindow, rcClient;
  412. BOOL fResizeBuddy = FALSE;
  413. GetWindowRect(_hwnd, &rcWindow);
  414. GetClientRect(_hwnd, &rcClient);
  415. // Prepare a buddy size data block
  416. GBNQUERYBUDDYSIZE qbs;
  417. qbs.cy = pwp->cy - (RECTHEIGHT(rcWindow) - RECTHEIGHT(rcClient));
  418. qbs.cx = pwp->cx - (RECTWIDTH(rcWindow) - RECTWIDTH(rcClient));
  419. if (_dwBuddyFlags & GBBF_HSLAVE) // prevent external horz resizing
  420. {
  421. pwp->cx = RECTWIDTH(rcWindow);
  422. // If we're being resized in the vert dir, query for
  423. // optimal buddy width for this height and adjust
  424. if (_dwBuddyFlags & GBBF_VRESIZE && RECTHEIGHT(rcWindow) != pwp->cy)
  425. {
  426. if (SendNotify(GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs) && qbs.cx >= 0)
  427. {
  428. // if the owner wants the buddy width to change, do it now.
  429. LONG cxNew = qbs.cx + (RECTWIDTH(rcWindow) - RECTWIDTH(rcClient));
  430. fResizeBuddy = cxNew != pwp->cx;
  431. pwp->cx = cxNew;
  432. }
  433. }
  434. }
  435. if (_dwBuddyFlags & GBBF_VSLAVE) // prevent external vert resizing
  436. {
  437. pwp->cy = RECTHEIGHT(rcWindow);
  438. // If we're being resized in the horz dir, query for
  439. // optimal buddy height for this horizontal and adjust
  440. if (_dwBuddyFlags & GBBF_HRESIZE && RECTWIDTH(rcWindow) != pwp->cx)
  441. {
  442. if (SendNotify(GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs) && qbs.cy >= 0)
  443. {
  444. LONG cyNew = qbs.cy + (RECTHEIGHT(rcWindow) - RECTHEIGHT(rcClient));
  445. fResizeBuddy = cyNew != pwp->cy;
  446. pwp->cy = cyNew;
  447. }
  448. }
  449. }
  450. if (fResizeBuddy)
  451. {
  452. _fInLayout = TRUE;
  453. SetWindowPos(_hwndBuddy, NULL, 0, 0, qbs.cx, qbs.cy,
  454. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  455. _fInLayout = FALSE;
  456. }
  457. }
  458. // enforce minimum height:
  459. if (pwp->cy < _sizeCaption.cy)
  460. pwp->cy = _sizeCaption.cy;
  461. return 0;
  462. }
  463. LRESULT CGroupBtn::OnSize(WPARAM flags, LONG cx, LONG cy)
  464. {
  465. DoLayout();
  466. return 0;
  467. }
  468. void CGroupBtn::DoLayout(BOOL bNewBuddy)
  469. {
  470. if (!_fInLayout && IsWindow(_hwndBuddy))
  471. {
  472. RECT rcWindow, rcThis, rcBuddy;
  473. DWORD dwSwpBuddy = SWP_NOACTIVATE,
  474. dwSwpThis = SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE;
  475. BOOL fReposThis = FALSE;
  476. SIZE sizeNew;
  477. GetClientRect(_hwnd, &rcThis);
  478. GetWindowRect(_hwnd, &rcWindow);
  479. // get rectangles in parent coords
  480. MapWindowPoints(_hwnd, GetParent(_hwnd), (LPPOINT)&rcThis, POINTSPERRECT);
  481. MapWindowPoints(HWND_DESKTOP, GetParent(_hwnd), (LPPOINT)&rcWindow, POINTSPERRECT);
  482. _MapWindowRect(_hwndBuddy, GetParent(_hwnd), &rcBuddy);
  483. // If we need to reposition ourself to the buddy,
  484. // calculate the new size now.
  485. if (_dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE))
  486. CalcWindowSizeForClient(&rcThis, &rcWindow, &rcBuddy, &sizeNew);
  487. // Resize buddy according to size.
  488. if (_dwBuddyFlags & GBBF_HRESIZE)
  489. {
  490. rcBuddy.right = rcBuddy.left + RECTWIDTH(rcThis);
  491. if (bNewBuddy && 0 == (_dwBuddyFlags & GBBF_VRESIZE))
  492. {
  493. // query height
  494. GBNQUERYBUDDYSIZE qbs;
  495. qbs.cx = RECTWIDTH(rcThis);
  496. qbs.cy = -1;
  497. if (SendNotify(GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs) && qbs.cy >= 0)
  498. rcBuddy.bottom = rcBuddy.top + qbs.cy;
  499. }
  500. }
  501. else if (_dwBuddyFlags & GBBF_HSLAVE)
  502. {
  503. rcWindow.right = rcWindow.left + sizeNew.cx;
  504. fReposThis = TRUE;
  505. }
  506. if (_dwBuddyFlags & GBBF_VRESIZE)
  507. {
  508. rcBuddy.bottom = rcBuddy.top + RECTHEIGHT(rcThis);
  509. if (bNewBuddy && 0 == (_dwBuddyFlags & GBBF_HRESIZE))
  510. {
  511. // query width
  512. GBNQUERYBUDDYSIZE qbs;
  513. qbs.cx = -1;
  514. qbs.cy = RECTHEIGHT(rcThis);
  515. if (SendNotify(GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs) && qbs.cx >= 0)
  516. rcBuddy.right = rcBuddy.left + qbs.cx;
  517. }
  518. }
  519. else if (_dwBuddyFlags & GBBF_VSLAVE)
  520. {
  521. rcWindow.bottom = rcWindow.top + sizeNew.cy;
  522. fReposThis = TRUE;
  523. }
  524. if (_dwBuddyFlags & GBBF_HSCROLL)
  525. {
  526. /* not implemented */
  527. }
  528. if (_dwBuddyFlags & GBBF_VSCROLL)
  529. {
  530. /* not implemented */
  531. }
  532. // reposition ourself and update our client rect.
  533. if (fReposThis)
  534. {
  535. _fInLayout = TRUE;
  536. SetWindowPos(_hwnd, NULL, 0, 0,
  537. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow), dwSwpThis);
  538. _fInLayout = FALSE;
  539. GetClientRect(_hwnd, &rcThis);
  540. MapWindowPoints(_hwnd, GetParent(_hwnd), (LPPOINT)&rcThis, POINTSPERRECT);
  541. }
  542. // slide buddy into client area and reposition
  543. OffsetRect(&rcBuddy, rcThis.left - rcBuddy.left, rcThis.top - rcBuddy.top);
  544. _fInLayout = TRUE;
  545. SetWindowPos(_hwndBuddy, _hwnd, rcBuddy.left, rcBuddy.top,
  546. RECTWIDTH(rcBuddy), RECTHEIGHT(rcBuddy), dwSwpBuddy);
  547. _fInLayout = FALSE;
  548. }
  549. }
  550. // GBM_SETPLACEMENT handler
  551. BOOL CGroupBtn::SetPlacement(PGBPLACEMENT pgbp)
  552. {
  553. RECT rcWindow, rcClient;
  554. SIZE sizeDelta = {0};
  555. DWORD dwFlags = SWP_NOZORDER|SWP_NOACTIVATE;
  556. _MapWindowRect(GetParent(_hwnd), &rcWindow);
  557. CalcClientRect(&rcWindow, &rcClient);
  558. // establish whether we need to resize
  559. if ((pgbp->x < 0 || pgbp->x == rcWindow.left) &&
  560. (pgbp->y < 0 || pgbp->y == rcWindow.top))
  561. dwFlags |= SWP_NOMOVE;
  562. // compute horizontal placement
  563. if (pgbp->x >= 0) // fixed horz origin requested
  564. OffsetRect(&rcWindow, pgbp->x - rcWindow.left, 0);
  565. if (pgbp->cx >= 0) // fixed width requested
  566. rcWindow.right = rcWindow.left + pgbp->cx;
  567. else
  568. {
  569. if (pgbp->cxBuddy >= 0) // client width requested
  570. sizeDelta.cx = pgbp->cxBuddy - RECTWIDTH(rcClient);
  571. rcWindow.right += sizeDelta.cx;
  572. }
  573. // compute vertical placement
  574. if (pgbp->y >= 0) // fixed vert origin requested
  575. OffsetRect(&rcWindow, 0, pgbp->y - rcWindow.top);
  576. if (pgbp->cy >= 0) // fixed height requested
  577. rcWindow.bottom = rcWindow.top + pgbp->cy;
  578. else
  579. {
  580. if (pgbp->cyBuddy >= 0) // client height requested
  581. sizeDelta.cy = pgbp->cyBuddy - RECTHEIGHT(rcClient);
  582. rcWindow.bottom += sizeDelta.cy;
  583. }
  584. if (pgbp->hdwp && (-1 != (LONG_PTR)pgbp->hdwp))
  585. DeferWindowPos(pgbp->hdwp, _hwnd, NULL, rcWindow.left, rcWindow.top,
  586. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow),
  587. dwFlags);
  588. else
  589. SetWindowPos(_hwnd, NULL, rcWindow.left, rcWindow.top,
  590. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow),
  591. dwFlags);
  592. // stuff resulting rects
  593. pgbp->rcWindow = rcWindow;
  594. return CalcClientRect(&rcWindow, &pgbp->rcBuddy);
  595. }
  596. BOOL CGroupBtn::SetBuddy(HWND hwnd, ULONG dwFlags)
  597. {
  598. // If we already have a buddy, unhook ourselves
  599. //
  600. if (_hwndBuddy)
  601. {
  602. if (IsWindow(_hwndBuddy) && _pfnBuddy)
  603. {
  604. SetWindowLongPtr(_hwndBuddy, GWLP_USERDATA, (LONG_PTR)NULL);
  605. SetWindowLongPtr(_hwndBuddy, GWLP_WNDPROC, (LONG_PTR)_pfnBuddy);
  606. }
  607. _hwndBuddy = NULL;
  608. _pfnBuddy = NULL;
  609. }
  610. // Handle an invalid window...
  611. if (!IsWindow(hwnd))
  612. hwnd = NULL;
  613. // If we're being buddy'd with a window, hook it
  614. //
  615. if (hwnd)
  616. {
  617. if (dwFlags & (GBBF_HSLAVE|GBBF_VSLAVE))
  618. {
  619. // subclass the buddy
  620. _pfnBuddy = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)s_BuddyProc);
  621. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
  622. }
  623. _hwndBuddy = hwnd;
  624. _dwBuddyFlags = dwFlags;
  625. DoLayout(TRUE);
  626. }
  627. return TRUE;
  628. }
  629. // WM_NCCREATE handler
  630. void CGroupBtn::NcCreate(LPCREATESTRUCT lpcs)
  631. {
  632. // assign user data
  633. SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
  634. // enforce window style bits
  635. lpcs->style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
  636. lpcs->dwExStyle |= WS_EX_TRANSPARENT;
  637. SetWindowLong(_hwnd, GWL_STYLE, lpcs->style);
  638. SetWindowLong(_hwnd, GWL_EXSTYLE, lpcs->dwExStyle);
  639. // enforce min height
  640. SetText(lpcs->lpszName);
  641. if (lpcs->cy < _sizeCaption.cy)
  642. {
  643. lpcs->cy = _sizeCaption.cy;
  644. SetWindowPos(_hwnd, NULL, 0,0, lpcs->cx, lpcs->cy,
  645. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  646. }
  647. }
  648. // WM_NCCALCSIZE handler
  649. LRESULT CGroupBtn::NcCalcSize(BOOL fCalcValidRects, LPNCCALCSIZE_PARAMS pnccs)
  650. {
  651. LRESULT lRet = FALSE;
  652. RECT rcClient;
  653. if (fCalcValidRects && CalcClientRect(&pnccs->rgrc[0], &rcClient))
  654. {
  655. pnccs->rgrc[1] = pnccs->rgrc[2];
  656. pnccs->rgrc[0] = pnccs->rgrc[2] = rcClient;
  657. return WVR_VALIDRECTS;
  658. }
  659. return lRet;
  660. }
  661. // WM_NCPAINT handler
  662. void CGroupBtn::NcPaint(HRGN hrgn)
  663. {
  664. RECT rcWindow;
  665. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  666. HDC hdc;
  667. GetWindowRect(_hwnd, &rcWindow);
  668. OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
  669. if ((hdc = GetWindowDC(_hwnd)) != NULL)
  670. {
  671. if (dwStyle & WS_BORDER)
  672. {
  673. HBRUSH hbr = CreateSolidBrush(COLOR_WINDOWFRAME);
  674. if (hbr)
  675. {
  676. FrameRect(hdc, &rcWindow, hbr);
  677. DeleteObject(hbr);
  678. }
  679. }
  680. rcWindow.bottom = rcWindow.top + _sizeCaption.cy;
  681. SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  682. SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  683. ExtTextOut(hdc, rcWindow.left, rcWindow.top,
  684. ETO_OPAQUE, &rcWindow, NULL, 0, NULL);
  685. InflateRect(&rcWindow, -CAPTION_HPADDING, -(CAPTION_VPADDING/2));
  686. HFONT hfPrev = (HFONT)SelectObject(hdc, GetFont());
  687. ExtTextOut(hdc, rcWindow.left, rcWindow.top,
  688. ETO_OPAQUE, &rcWindow, _pszCaption,
  689. _pszCaption ? lstrlen(_pszCaption) : 0, NULL);
  690. SelectObject(hdc, hfPrev);
  691. if (0 == (_fKeyboardCues & UISF_HIDEFOCUS))
  692. {
  693. if (GetFocus() == _hwnd)
  694. {
  695. rcWindow.right = rcWindow.left + _sizeCaption.cx + 1;
  696. InflateRect(&rcWindow, 1, 0);
  697. DrawFocusRect(hdc, &rcWindow);
  698. }
  699. }
  700. ReleaseDC(_hwnd, hdc);
  701. }
  702. }
  703. // WM_NCMOUSEMOVE handler
  704. LRESULT CGroupBtn::NcMouseMove(WPARAM nHittest, LONG x, LONG y)
  705. {
  706. if (HTCAPTION == nHittest)
  707. {
  708. RECT rc;
  709. POINT pt;
  710. GetWindowRect(_hwnd, &rc);
  711. rc.bottom = rc.top + _sizeCaption.cy;
  712. rc.right = rc.left + _sizeCaption.cx;
  713. InflateRect(&rc, 0, -(CAPTION_VPADDING/2));
  714. pt.x = x;
  715. pt.y = y;
  716. if (PtInRect(&rc, pt))
  717. {
  718. HCURSOR hc = GetHandCursor();
  719. if (hc != NULL)
  720. {
  721. SetCursor(hc);
  722. return 0;
  723. }
  724. }
  725. }
  726. return DefWindowProc(_hwnd, WM_NCMOUSEMOVE, nHittest, MAKELPARAM(x, y));
  727. }
  728. // WM_NCHITTEST handler
  729. LRESULT CGroupBtn::NcHitTest(LONG x, LONG y)
  730. {
  731. POINT pt;
  732. RECT rc, rcClient;
  733. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  734. pt.x = x;
  735. pt.y = y;
  736. GetWindowRect(_hwnd, &rc);
  737. CalcClientRect(&rc, &rcClient);
  738. if (PtInRect(&rcClient, pt))
  739. return HTTRANSPARENT;
  740. if (PtInRect(&rc, pt))
  741. {
  742. if (dwStyle & WS_BORDER)
  743. {
  744. if (pt.x == rc.left ||
  745. pt.x == rc.right ||
  746. pt.y == rc.bottom)
  747. return HTBORDER;
  748. }
  749. return HTCAPTION;
  750. }
  751. return HTNOWHERE;
  752. }
  753. LRESULT CGroupBtn::NcButtonDown(UINT nMsg, WPARAM nHittest, const POINTS& pts)
  754. {
  755. LRESULT lRet = 0;
  756. if (HTCAPTION == nHittest)
  757. {
  758. SetCursor(GetHandCursor());
  759. MODIFY_CAPTURE(CF_SETCAPTURE, 0);
  760. if (GetFocus() != _hwnd)
  761. {
  762. MODIFY_CAPTURE(CF_SETFOCUS, 0);
  763. EnableNotifications(FALSE); // so the host doesn't reposition the link.
  764. SetFocus(_hwnd);
  765. EnableNotifications(TRUE);
  766. }
  767. SetCapture(_hwnd);
  768. }
  769. else
  770. lRet = DefWindowProc(_hwnd, nMsg, nHittest, MAKELONG(pts.x, pts.y));
  771. return lRet;
  772. }
  773. LRESULT CGroupBtn::ButtonUp(UINT nMsg, WPARAM nHittest, const POINTS& pts)
  774. {
  775. if (TEST_CAPTURE(CF_SETCAPTURE))
  776. {
  777. ReleaseCapture();
  778. MODIFY_CAPTURE(0, CF_SETCAPTURE);
  779. POINT ptScrn;
  780. ptScrn.x = pts.x;
  781. ptScrn.y = pts.y;
  782. MapWindowPoints(_hwnd, HWND_DESKTOP, &ptScrn, 1);
  783. LRESULT nHittest = SendMessage(_hwnd, WM_NCHITTEST, 0, MAKELONG(ptScrn.x, ptScrn.y));
  784. if (HTCAPTION == nHittest)
  785. {
  786. switch (nMsg)
  787. {
  788. case WM_LBUTTONUP:
  789. SendNotify(NM_CLICK);
  790. break;
  791. case WM_RBUTTONUP:
  792. SendNotify(NM_RCLICK);
  793. break;
  794. }
  795. }
  796. }
  797. if (TEST_CAPTURE(CF_SETFOCUS))
  798. {
  799. MODIFY_CAPTURE(0, CF_SETFOCUS);
  800. if (GetFocus() == _hwnd) // if we still have the focus...
  801. SendNotify(NM_SETFOCUS);
  802. }
  803. return 0;
  804. }
  805. // Non-client mouse click/dblclk handler
  806. LRESULT CGroupBtn::NcDblClick(UINT nMsg, WPARAM nHittest, LPARAM lParam)
  807. {
  808. LRESULT lRet = 0;
  809. if (HTCAPTION == nHittest)
  810. {
  811. SetFocus(_hwnd);
  812. lRet = DefWindowProc(_hwnd, nMsg, HTCLIENT, lParam);
  813. switch (nMsg)
  814. {
  815. case WM_NCLBUTTONDBLCLK:
  816. SendNotify(NM_DBLCLK);
  817. break;
  818. case WM_NCRBUTTONDBLCLK:
  819. SendNotify(NM_RDBLCLK);
  820. break;
  821. }
  822. }
  823. else
  824. lRet = DefWindowProc(_hwnd, nMsg, nHittest, lParam);
  825. return lRet;
  826. }
  827. LONG CGroupBtn::EnableNotifications(BOOL bEnable)
  828. {
  829. if (bEnable)
  830. {
  831. if (_cNotifyLocks > 0)
  832. _cNotifyLocks--;
  833. }
  834. else
  835. _cNotifyLocks++;
  836. return _cNotifyLocks;
  837. }
  838. // WM_NOTIFY transmit helper
  839. LRESULT CGroupBtn::SendNotify(int nCode, IN OPTIONAL NMHDR* pnmh)
  840. {
  841. if (0 == _cNotifyLocks)
  842. {
  843. NMHDR hdr;
  844. if (NULL == pnmh)
  845. pnmh = &hdr;
  846. pnmh->hwndFrom = _hwnd;
  847. pnmh->idFrom = GetDlgCtrlID(_hwnd);
  848. pnmh->code = nCode;
  849. return SendMessage(GetParent(_hwnd), WM_NOTIFY, hdr.idFrom, (LPARAM)pnmh);
  850. }
  851. return 0;
  852. }
  853. LRESULT CALLBACK CGroupBtn::s_GroupBtnWndProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  854. {
  855. CGroupBtn *pThis = (CGroupBtn *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  856. if (!pThis && (WM_NCCREATE == wMsg))
  857. {
  858. pThis = new CGroupBtn(hDlg);
  859. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pThis);
  860. }
  861. if (pThis)
  862. return pThis->WndProc(hDlg, wMsg, wParam, lParam);
  863. return DefWindowProc(hDlg, wMsg, wParam, lParam);
  864. }
  865. LRESULT CGroupBtn::WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  866. {
  867. LRESULT lRet = 0;
  868. switch (nMsg)
  869. {
  870. case WM_NCHITTEST:
  871. {
  872. POINTS pts = MAKEPOINTS(lParam);
  873. return NcHitTest(pts.x, pts.y);
  874. }
  875. case WM_NCMOUSEMOVE:
  876. {
  877. POINTS pts = MAKEPOINTS(lParam);
  878. return NcMouseMove(wParam, pts.x, pts.y);
  879. }
  880. case WM_NCCALCSIZE:
  881. return NcCalcSize((BOOL)wParam, (LPNCCALCSIZE_PARAMS)lParam);
  882. case WM_NCPAINT:
  883. NcPaint((HRGN)wParam);
  884. return 0;
  885. case WM_WINDOWPOSCHANGING:
  886. return WindowPosChanging((LPWINDOWPOS)lParam);
  887. case WM_SIZE:
  888. {
  889. POINTS pts = MAKEPOINTS(lParam);
  890. return OnSize(wParam, pts.x, pts.y);
  891. }
  892. case WM_DESTROY:
  893. if (IsWindow(_hwndBuddy))
  894. DestroyWindow(_hwndBuddy);
  895. break;
  896. case WM_ERASEBKGND:
  897. return TRUE; // transparent: no erase bkgnd
  898. case WM_NCLBUTTONDOWN:
  899. case WM_NCRBUTTONDOWN:
  900. {
  901. POINTS pts = MAKEPOINTS(lParam);
  902. return NcButtonDown(nMsg, wParam, pts);
  903. }
  904. case WM_LBUTTONUP:
  905. case WM_RBUTTONUP:
  906. {
  907. POINTS pts = MAKEPOINTS(lParam);
  908. return ButtonUp(nMsg, wParam, pts);
  909. }
  910. case WM_NCLBUTTONDBLCLK:
  911. case WM_NCRBUTTONDBLCLK:
  912. return NcDblClick(nMsg, wParam, lParam);
  913. case WM_SHOWWINDOW:
  914. if (IsWindow(_hwndBuddy))
  915. ShowWindow(_hwndBuddy, wParam ? SW_SHOW : SW_HIDE);
  916. break;
  917. case WM_SETTEXT:
  918. SetText((LPCTSTR)lParam);
  919. return TRUE;
  920. case WM_GETTEXT:
  921. return GetText((LPTSTR)lParam, (int)wParam);
  922. case WM_SETFONT:
  923. SetFont((HFONT)wParam);
  924. if (lParam /* fRedraw */)
  925. InvalidateRect(hwnd, NULL, TRUE);
  926. break;
  927. case WM_CAPTURECHANGED:
  928. if (lParam /* NULL if we called ReleaseCapture() */)
  929. OnCaptureLost((HWND)lParam);
  930. break;
  931. case WM_SETFOCUS:
  932. NcPaint((HRGN)1);
  933. SendNotify(NM_SETFOCUS);
  934. break;
  935. case WM_KILLFOCUS:
  936. NcPaint((HRGN)1);
  937. SendNotify(NM_KILLFOCUS);
  938. break;
  939. case WM_GETDLGCODE:
  940. {
  941. MSG* pmsg;
  942. lRet = DLGC_BUTTON|DLGC_UNDEFPUSHBUTTON;
  943. if ((pmsg = (MSG*)lParam))
  944. {
  945. if ((WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message))
  946. {
  947. switch (pmsg->wParam)
  948. {
  949. case VK_RETURN:
  950. case VK_SPACE:
  951. lRet |= DLGC_WANTALLKEYS;
  952. break;
  953. }
  954. }
  955. else if (WM_CHAR == pmsg->message && VK_RETURN == pmsg->wParam)
  956. {
  957. // Eat VK_RETURN WM_CHARs; we don't want
  958. // Dialog manager to beep when IsDialogMessage gets it.
  959. return lRet |= DLGC_WANTMESSAGE;
  960. }
  961. }
  962. return lRet;
  963. }
  964. case WM_KEYDOWN:
  965. case WM_KEYUP:
  966. case WM_CHAR:
  967. switch (wParam)
  968. {
  969. case VK_RETURN:
  970. case VK_SPACE:
  971. if (WM_KEYDOWN == nMsg)
  972. SendNotify(NM_RETURN);
  973. return 0;
  974. }
  975. break;
  976. case WM_UPDATEUISTATE:
  977. if (_HandleWM_UPDATEUISTATE(wParam, lParam, &_fKeyboardCues))
  978. SendMessage(hwnd, WM_NCPAINT, 1, 0);
  979. break;
  980. case GBM_SETPLACEMENT:
  981. if (lParam)
  982. return SetPlacement((PGBPLACEMENT)lParam);
  983. return 0;
  984. case GBM_SETDROPSTATE: // WPARAM: BOOL fDropped, LPARAM: n/a, return: BOOL
  985. return 0;
  986. case GBM_GETDROPSTATE: // WPARAM: n/a, LPARAM: n/a, return: BOOL fDropped
  987. return 0;
  988. case GBM_SENDNOTIFY:
  989. SendNotify((int)wParam);
  990. break;
  991. case WM_NCCREATE:
  992. NcCreate((LPCREATESTRUCT)lParam);
  993. break;
  994. case WM_NCDESTROY:
  995. lRet = DefWindowProc(hwnd, nMsg, wParam, lParam);
  996. SetWindowPtr(hwnd, GWLP_USERDATA, NULL);
  997. _hwnd = NULL;
  998. Release();
  999. return lRet;
  1000. case WM_CREATE:
  1001. _InitializeUISTATE(hwnd, &_fKeyboardCues);
  1002. SetText(((LPCREATESTRUCT)lParam)->lpszName);
  1003. break;
  1004. case GBM_SETBUDDY: // WPARAM: HWND hwndBuddy, LPARAM: MAKELPARAM(cxMargin, cyMargin), return: BOOL
  1005. return SetBuddy((HWND)wParam, (ULONG)lParam);
  1006. case GBM_GETBUDDY: // WPARAM: n/a, LPARAM: n/a, return: HWND
  1007. return (LRESULT)_hwndBuddy;
  1008. default:
  1009. // oleacc defs thunked for WINVER < 0x0500
  1010. if ((WM_GETOBJECT == nMsg) && (OBJID_CLIENT == (DWORD)lParam || OBJID_TITLEBAR == (DWORD)lParam))
  1011. return LresultFromObject(IID_IAccessible, wParam, SAFECAST(this, IAccessible*));
  1012. break;
  1013. }
  1014. return DefWindowProc(hwnd, nMsg, wParam, lParam);
  1015. }
  1016. LRESULT CGroupBtn::s_BuddyProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  1017. {
  1018. CGroupBtn *pBtn = (CGroupBtn*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1019. switch (nMsg)
  1020. {
  1021. case WM_SIZE:
  1022. {
  1023. LRESULT lRet = CallWindowProc(pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam);
  1024. if (!pBtn->_fInLayout)
  1025. pBtn->DoLayout();
  1026. return lRet;
  1027. }
  1028. case WM_DESTROY:
  1029. {
  1030. WNDPROC pfn = pBtn->_pfnBuddy;
  1031. pBtn->SetBuddy(NULL, 0);
  1032. return CallWindowProc(pfn, hwnd, nMsg, wParam, lParam);
  1033. }
  1034. }
  1035. return pBtn->_pfnBuddy ? CallWindowProc(pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam) : 0;
  1036. }
  1037. // CAccessibleBase IUnknown impl
  1038. STDMETHODIMP CAccessibleBase::QueryInterface(REFIID riid, void** ppvObj)
  1039. {
  1040. static const QITAB qit[] =
  1041. {
  1042. QITABENT(CAccessibleBase, IDispatch),
  1043. QITABENT(CAccessibleBase, IAccessible),
  1044. QITABENT(CAccessibleBase, IOleWindow),
  1045. { 0 },
  1046. };
  1047. return QISearch(this, qit, riid, ppvObj);
  1048. }
  1049. STDMETHODIMP_(ULONG) CAccessibleBase::AddRef()
  1050. {
  1051. return InterlockedIncrement(&_cRef);
  1052. }
  1053. STDMETHODIMP_(ULONG) CAccessibleBase::Release()
  1054. {
  1055. ASSERT( 0 != _cRef );
  1056. ULONG cRef = InterlockedDecrement(&_cRef);
  1057. if ( 0 == cRef )
  1058. {
  1059. delete this;
  1060. }
  1061. return cRef;
  1062. }
  1063. // CAccessibleBase IOleWindow impl
  1064. STDMETHODIMP CAccessibleBase::GetWindow(HWND* phwnd)
  1065. {
  1066. *phwnd = _hwnd;
  1067. return IsWindow(_hwnd) ? S_OK : S_FALSE;
  1068. }
  1069. // CAccessibleBase IDispatch impl
  1070. static HRESULT _accLoadTypeInfo(ITypeInfo** ppti)
  1071. {
  1072. ITypeLib* ptl;
  1073. HRESULT hr = LoadTypeLib(L"oleacc.dll", &ptl);
  1074. if (SUCCEEDED(hr))
  1075. {
  1076. hr = ptl->GetTypeInfoOfGuid(IID_IAccessible, ppti);
  1077. ATOMICRELEASE(ptl);
  1078. }
  1079. return hr;
  1080. }
  1081. STDMETHODIMP CAccessibleBase::GetTypeInfoCount(UINT * pctinfo)
  1082. {
  1083. *pctinfo = 1;
  1084. return S_OK;
  1085. }
  1086. STDMETHODIMP CAccessibleBase::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  1087. {
  1088. HRESULT hr = E_FAIL;
  1089. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1090. return hr;
  1091. *pptinfo = _ptiAcc;
  1092. (*pptinfo)->AddRef();
  1093. return S_OK;
  1094. }
  1095. STDMETHODIMP CAccessibleBase::GetIDsOfNames(
  1096. REFIID riid,
  1097. OLECHAR** rgszNames,
  1098. UINT cNames,
  1099. LCID lcid, DISPID * rgdispid)
  1100. {
  1101. HRESULT hr = E_FAIL;
  1102. if (IID_NULL != riid && IID_IAccessible != riid)
  1103. return DISP_E_UNKNOWNINTERFACE;
  1104. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1105. return hr;
  1106. return _ptiAcc->GetIDsOfNames(rgszNames, cNames, rgdispid);
  1107. }
  1108. STDMETHODIMP CAccessibleBase::Invoke(
  1109. DISPID dispidMember,
  1110. REFIID riid,
  1111. LCID lcid,
  1112. WORD wFlags,
  1113. DISPPARAMS * pdispparams,
  1114. VARIANT * pvarResult,
  1115. EXCEPINFO * pexcepinfo,
  1116. UINT * puArgErr)
  1117. {
  1118. HRESULT hr = E_FAIL;
  1119. if (IID_NULL != riid && IID_IAccessible != riid)
  1120. return DISP_E_UNKNOWNINTERFACE;
  1121. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1122. return hr;
  1123. return _ptiAcc->Invoke(this, dispidMember, wFlags, pdispparams,
  1124. pvarResult, pexcepinfo, puArgErr);
  1125. }
  1126. STDMETHODIMP CAccessibleBase::get_accParent(IDispatch ** ppdispParent)
  1127. {
  1128. *ppdispParent = NULL;
  1129. if (IsWindow(_hwnd))
  1130. return AccessibleObjectFromWindow(_hwnd, OBJID_WINDOW,
  1131. IID_PPV_ARG(IDispatch, ppdispParent));
  1132. return S_FALSE;
  1133. }
  1134. STDMETHODIMP CAccessibleBase::get_accChildCount(long * pcChildren)
  1135. {
  1136. *pcChildren = 0;
  1137. return S_OK;
  1138. }
  1139. STDMETHODIMP CAccessibleBase::get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild)
  1140. {
  1141. *ppdispChild = NULL;
  1142. return S_FALSE;
  1143. }
  1144. STDMETHODIMP CAccessibleBase::get_accValue(VARIANT varChild, BSTR* pbstrValue)
  1145. {
  1146. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1147. *pbstrValue = NULL;
  1148. return S_FALSE;
  1149. }
  1150. STDMETHODIMP CAccessibleBase::get_accDescription(VARIANT varChild, BSTR * pbstrDescription)
  1151. {
  1152. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1153. *pbstrDescription = NULL;
  1154. return S_FALSE;
  1155. }
  1156. STDMETHODIMP CAccessibleBase::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  1157. {
  1158. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1159. pvarRole->vt = VT_I4;
  1160. pvarRole->lVal = ROLE_SYSTEM_LINK;
  1161. return S_OK;
  1162. }
  1163. STDMETHODIMP CAccessibleBase::get_accState(VARIANT varChild, VARIANT *pvarState)
  1164. {
  1165. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1166. pvarState->vt = VT_I4;
  1167. pvarState->lVal = STATE_SYSTEM_DEFAULT ;
  1168. if (GetFocus() == _hwnd)
  1169. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  1170. else if (IsWindowEnabled(_hwnd))
  1171. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  1172. if (!IsWindowVisible(_hwnd))
  1173. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  1174. return S_OK;
  1175. }
  1176. STDMETHODIMP CAccessibleBase::get_accHelp(VARIANT varChild, BSTR* pbstrHelp)
  1177. {
  1178. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1179. *pbstrHelp = NULL;
  1180. return S_FALSE;
  1181. }
  1182. STDMETHODIMP CAccessibleBase::get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic)
  1183. {
  1184. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1185. *pbstrHelpFile = NULL;
  1186. *pidTopic = -1;
  1187. return S_FALSE;
  1188. }
  1189. STDMETHODIMP CAccessibleBase::get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut)
  1190. {
  1191. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1192. *pbstrKeyboardShortcut = NULL;
  1193. return S_FALSE;
  1194. }
  1195. STDMETHODIMP CAccessibleBase::get_accFocus(VARIANT FAR * pvarFocusChild)
  1196. {
  1197. HWND hwndFocus;
  1198. if ((hwndFocus = GetFocus()) == _hwnd || IsChild(_hwnd, hwndFocus))
  1199. {
  1200. pvarFocusChild->vt = VT_I4;
  1201. pvarFocusChild->lVal = CHILDID_SELF;
  1202. return S_OK;
  1203. }
  1204. return S_FALSE;
  1205. }
  1206. STDMETHODIMP CAccessibleBase::get_accSelection(VARIANT FAR * pvarSelectedChildren)
  1207. {
  1208. return get_accFocus(pvarSelectedChildren); // implemented same as focus.
  1209. }
  1210. STDMETHODIMP CAccessibleBase::get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction)
  1211. {
  1212. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1213. WCHAR wsz[128];
  1214. if (LoadStringW(HINST_THISDLL, GetDefaultActionStringID(), wsz, ARRAYSIZE(wsz)))
  1215. {
  1216. if (NULL == (*pbstrDefaultAction = SysAllocString(wsz)))
  1217. return E_OUTOFMEMORY;
  1218. return S_OK;
  1219. }
  1220. return E_FAIL;
  1221. }
  1222. STDMETHODIMP CAccessibleBase::accSelect(long flagsSelect, VARIANT varChild)
  1223. {
  1224. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1225. if (flagsSelect & SELFLAG_TAKEFOCUS)
  1226. {
  1227. SetFocus(_hwnd);
  1228. return S_OK;
  1229. }
  1230. return S_FALSE;
  1231. }
  1232. STDMETHODIMP CAccessibleBase::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  1233. {
  1234. RECT rc;
  1235. GetWindowRect(_hwnd, &rc);
  1236. *pxLeft = rc.left;
  1237. *pyTop = rc.top;
  1238. *pcxWidth = RECTWIDTH(rc);
  1239. *pcyHeight = RECTHEIGHT(rc);
  1240. varChild.vt = VT_I4;
  1241. varChild.lVal = CHILDID_SELF;
  1242. return S_OK;
  1243. }
  1244. STDMETHODIMP CAccessibleBase::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  1245. {
  1246. return S_FALSE;
  1247. }
  1248. STDMETHODIMP CAccessibleBase::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  1249. {
  1250. pvarChildAtPoint->vt = VT_I4;
  1251. pvarChildAtPoint->lVal = CHILDID_SELF;
  1252. return S_OK;
  1253. }
  1254. STDMETHODIMP CAccessibleBase::put_accName(VARIANT varChild, BSTR bstrName)
  1255. {
  1256. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1257. return S_FALSE;
  1258. }
  1259. STDMETHODIMP CAccessibleBase::put_accValue(VARIANT varChild, BSTR bstrValue)
  1260. {
  1261. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1262. return S_FALSE;
  1263. }
  1264. BOOL _HandleWM_UPDATEUISTATE(WPARAM wParam, LPARAM lParam, OUT UINT* puFlags)
  1265. {
  1266. UINT uFlags = *puFlags;
  1267. switch (LOWORD(wParam))
  1268. {
  1269. case UIS_CLEAR:
  1270. *puFlags &= ~(HIWORD(wParam));
  1271. break;
  1272. case UIS_SET:
  1273. *puFlags |= HIWORD(wParam);
  1274. break;
  1275. }
  1276. return uFlags != *puFlags;
  1277. }
  1278. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags)
  1279. {
  1280. HWND hwndParent = GetParent(hwnd);
  1281. *puFlags = (UINT)SendMessage(hwndParent, WM_QUERYUISTATE, 0, 0);
  1282. }