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.

1389 lines
42 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corp., 1991-2001 **/
  4. /**********************************************************************/
  5. /*
  6. CHKLIST.CPP
  7. This file contains the implementation of the CheckList control.
  8. */
  9. #include "stdafx.h"
  10. #include <windowsx.h>
  11. #include "chklist.h"
  12. #include "debug.h"
  13. #include "util.h"
  14. //
  15. // Text and Background colors
  16. //
  17. #define TEXT_COLOR COLOR_WINDOWTEXT
  18. #define BK_COLOR COLOR_WINDOW
  19. //
  20. // Default dimensions for child controls. All are in dialog units.
  21. // Currently only the column width is user-adjustable (via the
  22. // CLM_SETCOLUMNWIDTH message).
  23. //
  24. #define DEFAULT_COLUMN_WIDTH 32
  25. #define DEFAULT_CHECK_WIDTH 9
  26. #define DEFAULT_HORZ_SPACE 7
  27. #define DEFAULT_VERTICAL_SPACE 3
  28. #define DEFAULT_ITEM_HEIGHT 8
  29. //
  30. // 16 bits are used for the control ID's, divided into n bits for
  31. // the subitem (least significant) and 16-n bits for the item index.
  32. //
  33. // ID_SUBITEM_BITS can be adjusted to control the maximum number of
  34. // items and subitems. For example, to allow up to 7 subitems and 8k
  35. // items, set ID_SUBITEM_BITS to 3.
  36. //
  37. // Use the low 2 bits for the subitem index, the rest for the item index.
  38. // (4 subitems max, 16k items max)
  39. #define ID_SUBITEM_BITS 2
  40. #define ID_SUBITEM_MASK ((1 << ID_SUBITEM_BITS) - 1)
  41. #define GET_ITEM(id) ((id) >> ID_SUBITEM_BITS)
  42. #define GET_SUBITEM(id) ((id) & ID_SUBITEM_MASK)
  43. #define MAKE_CTRL_ID(i, s) (0xffff & (((i) << ID_SUBITEM_BITS) | ((s) & ID_SUBITEM_MASK)))
  44. #define MAKE_LABEL_ID(i) MAKE_CTRL_ID(i, 0)
  45. // Note that the subitem (column) index is one-based for the checkboxes
  46. // (the zero column is the label). The item (row) index is zero-based.
  47. #define MAX_CHECK_COLUMNS ID_SUBITEM_MASK
  48. typedef struct _USERDATA_STRUCT_LABEL
  49. {
  50. LPARAM lParam;
  51. int nLabelHeight;
  52. int itemIndex;
  53. } USERDATA_STRUCT_LABEL, *LPUSERDATA_STRUCT_LABEL;
  54. class CCheckList
  55. {
  56. private:
  57. LONG m_cItems;
  58. LONG m_cSubItems;
  59. RECT m_rcItemLabel;
  60. LONG m_nCheckPos[MAX_CHECK_COLUMNS];
  61. LONG m_cxCheckBox;
  62. LONG m_cxCheckColumn;
  63. int m_nDefaultVerticalSpace;
  64. int m_nDefaultItemHeight;
  65. int m_nNewItemYPos;
  66. HWND m_hwndCheckFocus;
  67. BOOL m_fInMessageEnable;
  68. int m_cWheelDelta;
  69. static UINT g_ucScrollLines;
  70. private:
  71. CCheckList(HWND hWnd, LPCREATESTRUCT lpcs);
  72. LRESULT MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl);
  73. void MsgPaint(HWND hWnd, HDC hdc);
  74. void MsgVScroll(HWND hWnd, int nCode, int nPos);
  75. void MsgMouseWheel(HWND hWnd, WORD fwFlags, int zDelta);
  76. void MsgButtonDown(HWND hWnd, WPARAM fwFlags, int xPos, int yPos);
  77. void MsgEnable(HWND hWnd, BOOL fEnabled);
  78. void MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight);
  79. LONG AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam);
  80. void SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState);
  81. LONG GetState(HWND hWnd, WORD iItem, WORD iSubItem);
  82. void SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn);
  83. void ResetContent(HWND hWnd);
  84. LONG GetVisibleCount(HWND hWnd);
  85. LONG GetTopIndex(HWND hWnd, LONG *pnAmountObscured = NULL);
  86. void SetTopIndex(HWND hWnd, LONG nIndex);
  87. void EnsureVisible(HWND hWnd, LONG nIndex);
  88. void DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw);
  89. public:
  90. HWND m_hWnd;
  91. static LRESULT CALLBACK WindowProc(HWND hWnd,
  92. UINT uMsg,
  93. WPARAM wParam,
  94. LPARAM lParam);
  95. };
  96. BOOL RegisterCheckListWndClass(void)
  97. {
  98. WNDCLASS wc;
  99. wc.style = 0;
  100. wc.lpfnWndProc = CCheckList::WindowProc;
  101. wc.cbClsExtra = 0;
  102. wc.cbWndExtra = 0;
  103. AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
  104. wc.hInstance = AfxGetInstanceHandle(); //hModule;
  105. wc.hIcon = NULL;
  106. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  107. wc.hbrBackground = (HBRUSH)(BK_COLOR+1);
  108. wc.lpszMenuName = NULL;
  109. wc.lpszClassName = TEXT(WC_CHECKLIST);
  110. return (BOOL)RegisterClass(&wc);
  111. }
  112. UINT CCheckList::g_ucScrollLines = (UINT)-1;
  113. CCheckList::CCheckList(HWND hWnd, LPCREATESTRUCT lpcs)
  114. : m_cItems(0), m_hwndCheckFocus(NULL), m_fInMessageEnable(FALSE), m_cWheelDelta(0)
  115. {
  116. TraceEnter(TRACE_CHECKLIST, "CCheckList::CCheckList");
  117. TraceAssert(hWnd != NULL);
  118. TraceAssert(lpcs != NULL); //Check lpcs before using it.
  119. m_hWnd = hWnd;
  120. //
  121. // Get number of check columns
  122. //
  123. if( lpcs ) //Raid #550912, yanggao.
  124. {
  125. m_cSubItems = lpcs->style & CLS_CHECKMASK;
  126. }
  127. // for wsecedit only
  128. if ( m_cSubItems > 3 ) {
  129. m_cSubItems = 3;
  130. }
  131. //
  132. // Convert default coordinates from dialog units to pixels
  133. //
  134. RECT rc;
  135. rc.left = DEFAULT_CHECK_WIDTH;
  136. rc.right = DEFAULT_COLUMN_WIDTH;
  137. rc.top = rc.bottom = 0;
  138. if( lpcs ) //Raid #550912, yanggao.
  139. {
  140. MapDialogRect(lpcs->hwndParent, &rc);
  141. }
  142. // Save the converted values
  143. m_cxCheckBox = rc.left;
  144. m_cxCheckColumn = rc.right;
  145. rc.left = DEFAULT_HORZ_SPACE;
  146. rc.top = DEFAULT_VERTICAL_SPACE;
  147. rc.right = 10; // bogus (unused)
  148. rc.bottom = DEFAULT_VERTICAL_SPACE + DEFAULT_ITEM_HEIGHT;
  149. if( lpcs ) //Raid #550912, yanggao.
  150. {
  151. MapDialogRect(lpcs->hwndParent, &rc);
  152. }
  153. // Save the converted values
  154. m_rcItemLabel = rc;
  155. m_nDefaultVerticalSpace = rc.top;
  156. m_nDefaultItemHeight = rc.bottom - rc.top;
  157. m_nNewItemYPos = rc.top;
  158. //
  159. // Get info for mouse wheel scrolling
  160. //
  161. if ((UINT)-1 == g_ucScrollLines)
  162. {
  163. g_ucScrollLines = 3; // default
  164. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
  165. }
  166. TraceLeaveVoid();
  167. }
  168. LRESULT
  169. CCheckList::MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl)
  170. {
  171. TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgCommand");
  172. // Should only get notifications from visible, enabled, check boxes
  173. //Check below expression before enter the message processing body.
  174. TraceAssert(GET_ITEM(idCmd) < m_cItems);
  175. TraceAssert(0 < GET_SUBITEM(idCmd) && GET_SUBITEM(idCmd) <= m_cSubItems);
  176. TraceAssert(hwndCtrl && IsWindowEnabled(hwndCtrl));
  177. if( !(GET_ITEM(idCmd) < m_cItems) || !(0 < GET_SUBITEM(idCmd) && GET_SUBITEM(idCmd) <= m_cSubItems) ||
  178. !(hwndCtrl && IsWindowEnabled(hwndCtrl)) ) //Raid #550912, yanggao.
  179. {
  180. return 0;
  181. }
  182. switch (wNotify)
  183. {
  184. case EN_SETFOCUS:
  185. {
  186. // Make the focus go to one of the checkboxes
  187. POINT pt;
  188. DWORD dwPos = GetMessagePos();
  189. pt.x = GET_X_LPARAM(dwPos);
  190. pt.y = GET_Y_LPARAM(dwPos);
  191. MapWindowPoints(NULL, hWnd, &pt, 1);
  192. MsgButtonDown(hWnd, 0, pt.x, pt.y);
  193. }
  194. break;
  195. case BN_CLICKED:
  196. {
  197. LPUSERDATA_STRUCT_LABEL lpUserData;
  198. NM_CHECKLIST nmc;
  199. nmc.hdr.hwndFrom = hWnd;
  200. nmc.hdr.idFrom = GetDlgCtrlID(hWnd);
  201. nmc.hdr.code = CLN_CLICK;
  202. nmc.iItem = GET_ITEM(idCmd);
  203. nmc.iSubItem = GET_SUBITEM(idCmd);
  204. nmc.dwState = (DWORD)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
  205. if (!IsWindowEnabled(hwndCtrl))
  206. nmc.dwState |= CLST_DISABLED;
  207. lpUserData = (LPUSERDATA_STRUCT_LABEL)
  208. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID(nmc.iItem)),
  209. GWLP_USERDATA);
  210. nmc.dwItemData = lpUserData->lParam;
  211. SendMessage(GetParent(hWnd),
  212. WM_NOTIFY,
  213. nmc.hdr.idFrom,
  214. (LPARAM)&nmc);
  215. }
  216. break;
  217. case BN_SETFOCUS:
  218. if (GetFocus() != hwndCtrl)
  219. {
  220. // This causes another BN_SETFOCUS
  221. SetFocus(hwndCtrl);
  222. }
  223. else
  224. {
  225. if (m_hwndCheckFocus != hwndCtrl) // Has the focus moved?
  226. {
  227. // Remember where the focus is
  228. m_hwndCheckFocus = hwndCtrl;
  229. // Make sure the row is scrolled into view
  230. EnsureVisible(hWnd, GET_ITEM(idCmd));
  231. }
  232. // Always draw the focus rect
  233. DrawCheckFocusRect(hWnd, hwndCtrl, TRUE);
  234. }
  235. break;
  236. case BN_KILLFOCUS:
  237. // Remove the focus rect
  238. m_hwndCheckFocus = NULL;
  239. DrawCheckFocusRect(hWnd, hwndCtrl, FALSE);
  240. break;
  241. }
  242. TraceLeaveValue(0);
  243. }
  244. void
  245. CCheckList::MsgPaint(HWND hWnd, HDC hdc)
  246. {
  247. if (hdc == NULL && m_hwndCheckFocus != NULL)
  248. {
  249. // This will cause a focus rect to be drawn after the window and
  250. // all checkboxes have been painted.
  251. PostMessage(hWnd,
  252. WM_COMMAND,
  253. GET_WM_COMMAND_MPS(GetDlgCtrlID(m_hwndCheckFocus), m_hwndCheckFocus, BN_SETFOCUS));
  254. }
  255. // Default paint
  256. DefWindowProc(hWnd, WM_PAINT, (WPARAM)hdc, 0);
  257. }
  258. void
  259. CCheckList::MsgVScroll(HWND hWnd, int nCode, int nPos)
  260. {
  261. UINT cScrollUnitsPerLine;
  262. SCROLLINFO si;
  263. si.cbSize = sizeof(si);
  264. si.fMask = SIF_ALL;
  265. if (!GetScrollInfo(hWnd, SB_VERT, &si))
  266. return;
  267. cScrollUnitsPerLine = m_rcItemLabel.bottom;
  268. // One page is always visible, so adjust the range to a more useful value
  269. si.nMax -= si.nPage - 1;
  270. switch (nCode)
  271. {
  272. case SB_LINEUP:
  273. // "line" is the height of one item (includes the space in between)
  274. nPos = si.nPos - cScrollUnitsPerLine;
  275. break;
  276. case SB_LINEDOWN:
  277. nPos = si.nPos + cScrollUnitsPerLine;
  278. break;
  279. case SB_PAGEUP:
  280. nPos = si.nPos - si.nPage;
  281. break;
  282. case SB_PAGEDOWN:
  283. nPos = si.nPos + si.nPage;
  284. break;
  285. case SB_TOP:
  286. nPos = si.nMin;
  287. break;
  288. case SB_BOTTOM:
  289. nPos = si.nMax;
  290. break;
  291. case SB_ENDSCROLL:
  292. nPos = si.nPos; // don't go anywhere
  293. break;
  294. case SB_THUMBTRACK:
  295. // Do nothing here to allow tracking
  296. // nPos = si.nPos; // Do this to prevent tracking
  297. case SB_THUMBPOSITION:
  298. // nothing to do here... nPos is passed in
  299. break;
  300. }
  301. // Make sure the new position is within the range
  302. if (nPos < si.nMin)
  303. nPos = si.nMin;
  304. else if (nPos > si.nMax)
  305. nPos = si.nMax;
  306. if (nPos != si.nPos) // are we moving?
  307. {
  308. SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
  309. ScrollWindow(hWnd, 0, si.nPos - nPos, NULL, NULL);
  310. }
  311. }
  312. void
  313. CCheckList::MsgMouseWheel(HWND hWnd, WORD fwFlags, int iWheelDelta)
  314. {
  315. int cDetants;
  316. if ((fwFlags & (MK_SHIFT | MK_CONTROL)) || 0 == g_ucScrollLines)
  317. return;
  318. TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgMouseWheel");
  319. // Update count of scroll amount
  320. m_cWheelDelta -= iWheelDelta;
  321. cDetants = m_cWheelDelta / WHEEL_DELTA;
  322. if (0 == cDetants)
  323. TraceLeaveVoid();
  324. m_cWheelDelta %= WHEEL_DELTA;
  325. if (WS_VSCROLL & GetWindowLong(hWnd, GWL_STYLE))
  326. {
  327. SCROLLINFO si;
  328. UINT cScrollUnitsPerLine;
  329. UINT cLinesPerPage;
  330. UINT cLinesPerDetant;
  331. // Get the scroll amount of one line
  332. cScrollUnitsPerLine = m_rcItemLabel.bottom;
  333. TraceAssert(cScrollUnitsPerLine > 0); //Check this expression.
  334. if( cScrollUnitsPerLine <= 0 ) //Raid #550912, yanggao.
  335. return;
  336. si.cbSize = sizeof(SCROLLINFO);
  337. si.fMask = SIF_PAGE | SIF_POS;
  338. if (!GetScrollInfo(hWnd, SB_VERT, &si))
  339. TraceLeaveVoid();
  340. // The size of a page is at least one line, and
  341. // leaves one line of overlap
  342. cLinesPerPage = (si.nPage - cScrollUnitsPerLine) / cScrollUnitsPerLine;
  343. cLinesPerPage = max(1, cLinesPerPage);
  344. // Don't scroll more than one page per detant
  345. cLinesPerDetant = min(cLinesPerPage, g_ucScrollLines);
  346. si.nPos += cDetants * cLinesPerDetant * cScrollUnitsPerLine;
  347. MsgVScroll(hWnd, SB_THUMBTRACK, si.nPos);
  348. }
  349. TraceLeaveVoid();
  350. }
  351. void
  352. CCheckList::MsgButtonDown(HWND hWnd, WPARAM /*fwFlags*/, int xPos, int yPos)
  353. {
  354. LONG nItemIndex;
  355. HWND hwndCheck;
  356. RECT rc;
  357. // Get position of the top visible item in client coords
  358. nItemIndex = GetTopIndex(hWnd);
  359. if (nItemIndex == -1)
  360. {
  361. return;
  362. }
  363. hwndCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(nItemIndex, 0));
  364. GetWindowRect(hwndCheck, &rc);
  365. MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2);
  366. // Find nearest item
  367. if( hWnd == m_hWnd ) //Raid #387542, 5/9/2001
  368. {
  369. POINT pos = {xPos,yPos};
  370. HWND ChildhWnd = ::ChildWindowFromPointEx(hWnd, pos, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED);
  371. if( ChildhWnd )
  372. {
  373. LPUSERDATA_STRUCT_LABEL pUserData = (LPUSERDATA_STRUCT_LABEL)GetWindowLongPtr(ChildhWnd, GWLP_USERDATA);
  374. if( pUserData )
  375. {
  376. nItemIndex = pUserData->itemIndex;
  377. }
  378. else
  379. {
  380. return;
  381. }
  382. }
  383. }
  384. // Set focus to first subitem that is enabled
  385. for (LONG j = 1; j <= m_cSubItems; j++)
  386. {
  387. int id = MAKE_CTRL_ID(nItemIndex, j);
  388. hwndCheck = GetDlgItem(hWnd, id); //Raid #prefast
  389. if (IsWindowEnabled(hwndCheck))
  390. {
  391. // Don't just SetFocus here. We sometimes call this during
  392. // EN_SETFOCUS, and USER doesn't like it when you mess with
  393. // focus during a focus change.
  394. //
  395. //SetFocus(hwndCheck);
  396. PostMessage(hWnd,
  397. WM_COMMAND,
  398. GET_WM_COMMAND_MPS(id, hwndCheck, BN_SETFOCUS));
  399. break;
  400. }
  401. }
  402. }
  403. void
  404. CCheckList::MsgEnable(HWND hWnd, BOOL fEnabled)
  405. {
  406. HWND hwndCurrentCheck;
  407. BOOL fCheckEnabled;
  408. if (!m_fInMessageEnable)
  409. {
  410. m_fInMessageEnable = TRUE;
  411. for (LONG i = 0; i < m_cItems; i++)
  412. {
  413. for (LONG j = 1; j <= m_cSubItems; j++)
  414. {
  415. hwndCurrentCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(i, j));
  416. fCheckEnabled = (BOOL) GetWindowLongPtr(hwndCurrentCheck, GWLP_USERDATA);
  417. //
  418. // If the user of the checklist control is disabling the control
  419. // altogether, or the current checkbox has been disabled singularly
  420. // then disable the checkbox
  421. //
  422. if (!fEnabled || !fCheckEnabled)
  423. {
  424. EnableWindow(hwndCurrentCheck, FALSE);
  425. }
  426. else
  427. {
  428. EnableWindow(hwndCurrentCheck, TRUE);
  429. }
  430. }
  431. }
  432. // Note that the main chklist window must remain enabled
  433. // for scrolling to work while "disabled".
  434. if (!fEnabled)
  435. EnableWindow(hWnd, TRUE);
  436. m_fInMessageEnable = FALSE;
  437. }
  438. }
  439. void
  440. CCheckList::MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight)
  441. {
  442. TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgSize");
  443. TraceAssert(hWnd != NULL); //Validate hWnd.
  444. if( !hWnd ) //Raid #550912, yanggao.
  445. return;
  446. if (dwSizeType == SIZE_RESTORED)
  447. {
  448. RECT rc;
  449. SCROLLINFO si;
  450. si.cbSize = sizeof(si);
  451. si.fMask = SIF_RANGE | SIF_PAGE;
  452. si.nMin = 0;
  453. si.nMax = m_nNewItemYPos - 1;
  454. si.nPage = nHeight;
  455. SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
  456. // Don't trust the width value passed in, since SetScrollInfo may
  457. // affect it if the scroll bar is turning on or off.
  458. GetClientRect(hWnd, &rc);
  459. nWidth = rc.right;
  460. // If the scrollbar is turned on, artificially bump up the width
  461. // by the width of the scrollbar, so the boxes don't jump to the left
  462. // when we have a scrollbar.
  463. if ((UINT)si.nMax >= si.nPage)
  464. nWidth += GetSystemMetrics(SM_CYHSCROLL);
  465. SetColumnWidth(hWnd, nWidth, m_cxCheckColumn);
  466. }
  467. TraceLeaveVoid();
  468. }
  469. LONG CCheckList::AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam)
  470. {
  471. HWND hwndPrev = 0;
  472. LPUSERDATA_STRUCT_LABEL lpUserData = 0;
  473. TraceEnter(TRACE_CHECKLIST, "CCheckList::AddItem");
  474. TraceAssert(hWnd != NULL);
  475. TraceAssert(pszLabel != NULL && !IsBadStringPtr(pszLabel, MAX_PATH));
  476. if ( !hWnd || !pszLabel || IsBadStringPtr(pszLabel, MAX_PATH) )
  477. return -1;
  478. lpUserData = new (USERDATA_STRUCT_LABEL);
  479. if ( lpUserData )
  480. {
  481. SCROLLINFO si;
  482. si.cbSize = sizeof(si);
  483. si.fMask = SIF_POS;
  484. si.nPos = 0;
  485. GetScrollInfo(hWnd, SB_VERT, &si);
  486. // Set the initial label height extra big so the control can wrap the text,
  487. // then reset it after creating the control.
  488. RECT rc;
  489. GetClientRect(hWnd, &rc);
  490. LONG nLabelHeight = rc.bottom;
  491. AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
  492. HMODULE hModule = AfxGetInstanceHandle();
  493. // Create a new label control
  494. HWND hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  495. TEXT("edit"),
  496. pszLabel,
  497. WS_CHILD | WS_VISIBLE | WS_GROUP | ES_MULTILINE | ES_READONLY | ES_LEFT,// | WS_GROUP,
  498. m_rcItemLabel.left,
  499. m_nNewItemYPos - si.nPos,
  500. m_rcItemLabel.right - m_rcItemLabel.left,
  501. nLabelHeight,
  502. hWnd,
  503. (HMENU)IntToPtr(MAKE_LABEL_ID(m_cItems)),
  504. hModule,
  505. NULL);
  506. if ( hwndNew )
  507. {
  508. HWND hwndEdit = hwndNew;
  509. //
  510. // Reset window height after word wrap has been done.
  511. //
  512. LONG nLineCount = (LONG) SendMessage(hwndNew, EM_GETLINECOUNT, 0, (LPARAM) 0);
  513. nLabelHeight = nLineCount * m_nDefaultItemHeight;
  514. SetWindowPos(hwndNew,
  515. NULL,
  516. 0,
  517. 0,
  518. m_rcItemLabel.right - m_rcItemLabel.left,
  519. nLabelHeight,
  520. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  521. //
  522. // Save item data
  523. //
  524. lpUserData->lParam = lParam;
  525. lpUserData->nLabelHeight = nLabelHeight;
  526. lpUserData->itemIndex = m_cItems; //Raid #387542
  527. SetLastError(0);
  528. SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) lpUserData); //Raid #286697, 4/4/2001
  529. if( 0 == GetLastError() )
  530. {
  531. // Set the font
  532. SendMessage(hwndNew,
  533. WM_SETFONT,
  534. SendMessage(GetParent(hWnd), WM_GETFONT, 0, 0),
  535. 0);
  536. // Set Z-order position just after the last checkbox. This keeps
  537. // tab order correct.
  538. if (m_cItems > 0)
  539. {
  540. hwndPrev = GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems - 1, m_cSubItems));
  541. SetWindowPos(hwndNew,
  542. hwndPrev,
  543. 0, 0, 0, 0,
  544. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  545. }
  546. // Create new checkboxes
  547. DWORD dwCheckStyle = WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_NOTIFY | BS_FLAT | BS_AUTOCHECKBOX;
  548. for (LONG j = 0; j < m_cSubItems; j++)
  549. {
  550. hwndPrev = hwndNew;
  551. hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  552. TEXT("BUTTON"),
  553. NULL,
  554. dwCheckStyle,
  555. m_nCheckPos[j],
  556. m_nNewItemYPos - si.nPos,
  557. m_cxCheckBox,
  558. m_rcItemLabel.bottom - m_rcItemLabel.top,
  559. hWnd,
  560. (HMENU)IntToPtr(MAKE_CTRL_ID(m_cItems, j + 1)),
  561. hModule,
  562. NULL);
  563. if (!hwndNew)
  564. {
  565. while (j >= 0)
  566. {
  567. DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems, j)));
  568. j--;
  569. }
  570. DestroyWindow (hwndEdit);
  571. delete lpUserData;
  572. TraceLeaveValue(-1);
  573. }
  574. // Set Z-order position just after the last checkbox. This keeps
  575. // tab order correct.
  576. SetWindowPos(hwndNew,
  577. hwndPrev,
  578. 0, 0, 0, 0,
  579. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  580. //
  581. // Default "enabled" to TRUE
  582. //
  583. SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) TRUE);
  584. // Only want this style on the first checkbox
  585. dwCheckStyle &= ~WS_GROUP;
  586. }
  587. // We now officially have a new item
  588. m_cItems++;
  589. // calculate Y pos for next item to be inserted
  590. m_nNewItemYPos += nLabelHeight + m_nDefaultVerticalSpace;
  591. //
  592. // The last thing is to set the scroll range
  593. //
  594. GetClientRect(hWnd, &rc);
  595. si.cbSize = sizeof(si);
  596. si.fMask = SIF_PAGE | SIF_RANGE;
  597. si.nMin = 0;
  598. si.nMax = m_nNewItemYPos - 1;
  599. si.nPage = rc.bottom;
  600. SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
  601. }
  602. else
  603. {
  604. delete lpUserData;
  605. DestroyWindow(hwndNew);
  606. }
  607. }
  608. else
  609. delete lpUserData;
  610. }
  611. TraceLeaveValue(m_cItems - 1); // return the index of the new item
  612. }
  613. void
  614. CCheckList::SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState)
  615. {
  616. HWND hwndCtrl;
  617. TraceEnter(TRACE_CHECKLIST, "CCheckList::SetState");
  618. //Check below expression.
  619. TraceAssert(hWnd != NULL);
  620. TraceAssert(iItem < m_cItems);
  621. TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
  622. if( !hWnd || !(iItem < m_cItems) || !(0 < iSubItem && iSubItem <= m_cSubItems) ) //Raid #550912, yanggao.
  623. return;
  624. if (iSubItem > 0)
  625. {
  626. hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
  627. if (hwndCtrl != NULL)
  628. {
  629. SetWindowLongPtr(hwndCtrl, GWLP_USERDATA, (LPARAM) !(lState & CLST_DISABLED));
  630. SendMessage(hwndCtrl, BM_SETCHECK, lState & CLST_CHECKED, 0);
  631. EnableWindow(hwndCtrl, !(lState & CLST_DISABLED));
  632. }
  633. }
  634. TraceLeaveVoid();
  635. }
  636. LONG
  637. CCheckList::GetState(HWND hWnd, WORD iItem, WORD iSubItem)
  638. {
  639. LONG lState = 0;
  640. TraceEnter(TRACE_CHECKLIST, "CCheckList::GetState");
  641. //Check below expressions.
  642. TraceAssert(hWnd != NULL);
  643. TraceAssert(iItem < m_cItems);
  644. TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
  645. if( !hWnd || !(iItem < m_cItems) || !(0 < iSubItem && iSubItem <= m_cSubItems) )//Raid #550912, yanggao.
  646. return lState;
  647. HWND hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
  648. if (hwndCtrl != NULL)
  649. {
  650. lState = (LONG)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
  651. TraceAssert(!(lState & BST_INDETERMINATE)); //Bogus Assert. yanggao
  652. if (!IsWindowEnabled(hwndCtrl))
  653. lState |= CLST_DISABLED;
  654. }
  655. TraceLeaveValue(lState);
  656. }
  657. void
  658. CCheckList::SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn)
  659. {
  660. LONG j;
  661. LPUSERDATA_STRUCT_LABEL pUserData;
  662. LONG nLabelHeight;
  663. TraceEnter(TRACE_CHECKLIST, "CCheckList::SetColumnWidth");
  664. //Check below expressions.
  665. TraceAssert(hWnd != NULL);
  666. TraceAssert(cxColumn > 10);
  667. if( !hWnd || !(cxColumn > 10) )//Raid #550912, yanggao.
  668. return;
  669. m_cxCheckColumn = cxColumn;
  670. if (m_cSubItems > 0)
  671. {
  672. m_nCheckPos[m_cSubItems-1] = cxDialog // dlg width
  673. - m_rcItemLabel.left // right margin
  674. - (cxColumn + m_cxCheckBox)/2; // 1/2 col & 1/2 checkbox
  675. for (j = m_cSubItems - 1; j > 0; j--)
  676. m_nCheckPos[j-1] = m_nCheckPos[j] - cxColumn;
  677. // (leftmost check pos) - (horz margin)
  678. m_rcItemLabel.right = m_nCheckPos[0] - m_rcItemLabel.left;
  679. }
  680. else
  681. m_rcItemLabel.right = cxDialog - m_rcItemLabel.left;
  682. LONG nTop = m_rcItemLabel.top;
  683. LONG nBottom = m_rcItemLabel.bottom;
  684. for (LONG i = 0; i < m_cItems; i++)
  685. {
  686. pUserData = (LPUSERDATA_STRUCT_LABEL)
  687. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  688. GWLP_USERDATA);
  689. if (pUserData != NULL)
  690. {
  691. nLabelHeight = pUserData->nLabelHeight;
  692. }
  693. else
  694. {
  695. nLabelHeight = nBottom - nTop;
  696. }
  697. MoveWindow(GetDlgItem(hWnd, MAKE_LABEL_ID(i)),
  698. m_rcItemLabel.left,
  699. nTop,
  700. m_rcItemLabel.right - m_rcItemLabel.left,
  701. nLabelHeight,
  702. FALSE);
  703. for (j = 0; j < m_cSubItems; j++)
  704. {
  705. MoveWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j + 1)),
  706. m_nCheckPos[j],
  707. nTop,
  708. m_cxCheckBox,
  709. nBottom - nTop,
  710. FALSE);
  711. }
  712. nTop += nLabelHeight + m_nDefaultVerticalSpace;
  713. nBottom += nLabelHeight + m_nDefaultVerticalSpace;
  714. }
  715. TraceLeaveVoid();
  716. }
  717. void
  718. CCheckList::ResetContent(HWND hWnd)
  719. {
  720. LPUSERDATA_STRUCT_LABEL pUserData;
  721. HWND hwndCurrentLabel;
  722. for (LONG i = 0; i < m_cItems; i++)
  723. {
  724. hwndCurrentLabel = GetDlgItem(hWnd, MAKE_LABEL_ID((int)i));
  725. pUserData = (LPUSERDATA_STRUCT_LABEL)
  726. GetWindowLongPtr( hwndCurrentLabel,
  727. GWLP_USERDATA);
  728. if (pUserData != NULL)
  729. {
  730. delete(pUserData);
  731. }
  732. DestroyWindow(hwndCurrentLabel);
  733. for (LONG j = 1; j <= m_cSubItems; j++)
  734. {
  735. DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j)));
  736. }
  737. }
  738. // Hide the scroll bar
  739. SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
  740. m_cItems = 0;
  741. }
  742. LONG
  743. CCheckList::GetVisibleCount(HWND hWnd)
  744. {
  745. LONG nCount = 0;
  746. RECT rc;
  747. LONG nTopIndex;
  748. LONG nAmountShown = 0;
  749. LONG nAmountObscured = 0;
  750. LPUSERDATA_STRUCT_LABEL pUserData;
  751. if (!GetClientRect(hWnd, &rc))
  752. {
  753. return 1;
  754. }
  755. nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
  756. if (nTopIndex == -1)
  757. {
  758. return 1;
  759. }
  760. while ((nTopIndex < m_cItems) && (nAmountShown < rc.bottom))
  761. {
  762. pUserData = (LPUSERDATA_STRUCT_LABEL)
  763. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  764. GWLP_USERDATA);
  765. nAmountShown += (m_nDefaultVerticalSpace + pUserData->nLabelHeight - nAmountObscured);
  766. nAmountObscured = 0; // nAmountObscured only matters for the first iteration where
  767. // the real top index's amount shown is being calculated
  768. nCount++;
  769. nTopIndex++;
  770. }
  771. //
  772. // since that last one may be obscured see if we need to adjust nCount
  773. //
  774. if (nAmountShown > rc.bottom)
  775. {
  776. nCount--;
  777. }
  778. return max(1, nCount);
  779. }
  780. LONG
  781. CCheckList::GetTopIndex(HWND hWnd, LONG *pnAmountObscured)
  782. {
  783. LONG nIndex = 0;
  784. LPUSERDATA_STRUCT_LABEL pUserData;
  785. SCROLLINFO si;
  786. si.cbSize = sizeof(si);
  787. si.fMask = SIF_POS;
  788. //
  789. // initialize
  790. //
  791. if (pnAmountObscured != NULL)
  792. {
  793. *pnAmountObscured = 0;
  794. }
  795. if (GetScrollInfo(hWnd, SB_VERT, &si) && m_rcItemLabel.bottom > 0)
  796. {
  797. pUserData = (LPUSERDATA_STRUCT_LABEL)
  798. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  799. GWLP_USERDATA);
  800. //
  801. // if there are no items get out
  802. //
  803. if (pUserData == NULL)
  804. {
  805. return -1;
  806. }
  807. while (si.nPos >= (m_nDefaultVerticalSpace + pUserData->nLabelHeight))
  808. {
  809. si.nPos -= (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
  810. nIndex++;
  811. pUserData = (LPUSERDATA_STRUCT_LABEL)
  812. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
  813. GWLP_USERDATA);
  814. }
  815. if (pnAmountObscured != NULL)
  816. {
  817. *pnAmountObscured = si.nPos;
  818. }
  819. }
  820. return nIndex;
  821. }
  822. void
  823. CCheckList::SetTopIndex(HWND hWnd, LONG nIndex)
  824. {
  825. int i;
  826. int nPos = 0;
  827. LPUSERDATA_STRUCT_LABEL pUserData;
  828. for (i=0; i<nIndex; i++)
  829. {
  830. pUserData = (LPUSERDATA_STRUCT_LABEL)
  831. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
  832. GWLP_USERDATA);
  833. nPos += (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
  834. }
  835. m_cWheelDelta = 0;
  836. MsgVScroll(hWnd, SB_THUMBPOSITION, nPos);
  837. }
  838. void
  839. CCheckList::EnsureVisible(HWND hWnd, LONG nItemIndex)
  840. {
  841. LONG nAmountObscured = 0;
  842. LONG nTopIndex;
  843. RECT rc;
  844. LPUSERDATA_STRUCT_LABEL pUserData;
  845. nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
  846. if (nTopIndex == -1)
  847. {
  848. return;
  849. }
  850. // Note that the top item may only be partially visible,
  851. // so we need to test for equality here. Raid #208449
  852. if (nItemIndex < nTopIndex)
  853. {
  854. SetTopIndex(hWnd, nItemIndex);
  855. }
  856. else if (nItemIndex == nTopIndex)
  857. {
  858. if (nAmountObscured != 0)
  859. {
  860. SetTopIndex(hWnd, nItemIndex);
  861. }
  862. }
  863. else
  864. {
  865. LONG nVisible = GetVisibleCount(hWnd);
  866. if (nItemIndex >= nTopIndex + nVisible)
  867. {
  868. if (!GetClientRect(hWnd, &rc))
  869. {
  870. //
  871. // This is just best effort
  872. //
  873. SetTopIndex(hWnd, nItemIndex - nVisible + 1);
  874. }
  875. else
  876. {
  877. //
  878. // Calculate what the top index should be to allow
  879. // nItemIndex to be fully visible
  880. //
  881. nTopIndex = nItemIndex + 1;
  882. do
  883. {
  884. nTopIndex--;
  885. pUserData = (LPUSERDATA_STRUCT_LABEL)
  886. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
  887. GWLP_USERDATA);
  888. if (pUserData != NULL)
  889. {
  890. rc.bottom -= (pUserData->nLabelHeight + m_nDefaultVerticalSpace);
  891. if (rc.bottom < 0)
  892. {
  893. nTopIndex++;
  894. }
  895. }
  896. else
  897. {
  898. //
  899. // Should not hit this, just added to make things safe
  900. //
  901. rc.bottom = 0;
  902. nTopIndex = 0;
  903. }
  904. } while (rc.bottom > 0);
  905. SetTopIndex(hWnd, nTopIndex);
  906. }
  907. }
  908. }
  909. }
  910. void
  911. CCheckList::DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw)
  912. {
  913. RECT rcCheck;
  914. TraceEnter(TRACE_CHECKLIST, "CCheckList::DrawCheckFocusRect");
  915. //Validate hWnd and hwndCheck.
  916. TraceAssert(hWnd != NULL);
  917. TraceAssert(hwndCheck != NULL);
  918. if( !hWnd || !(hwndCheck != NULL) ) //Raid #550912, yanggao.
  919. return;
  920. GetWindowRect(hwndCheck, &rcCheck);
  921. MapWindowPoints(NULL, hWnd, (LPPOINT)&rcCheck, 2);
  922. InflateRect(&rcCheck, 2, 2); // draw *outside* the checkbox
  923. HDC hdc = GetDC(hWnd);
  924. if (hdc)
  925. {
  926. // Always erase before drawing, since we may already be
  927. // partially visible and drawing is an XOR operation.
  928. // (Don't want to leave any turds on the screen.)
  929. FrameRect(hdc, &rcCheck, GetSysColorBrush(BK_COLOR));
  930. if (fDraw)
  931. {
  932. SetTextColor(hdc, GetSysColor(TEXT_COLOR));
  933. SetBkColor(hdc, GetSysColor(BK_COLOR));
  934. DrawFocusRect(hdc, &rcCheck);
  935. }
  936. ReleaseDC(hWnd, hdc);
  937. }
  938. TraceLeaveVoid();
  939. }
  940. LRESULT
  941. CALLBACK
  942. CCheckList::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  943. {
  944. LRESULT lResult = 0;
  945. LPUSERDATA_STRUCT_LABEL pUserData = NULL;
  946. CCheckList *pThis = (CCheckList*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  947. TraceEnter(TRACE_CHECKLIST, "CCheckList::WindowProc");
  948. TraceAssert(hWnd != NULL); //Validate hWnd.
  949. if( !hWnd ) //Raid #550912, yanggao.
  950. return lResult;
  951. switch (uMsg)
  952. {
  953. case WM_NCCREATE:
  954. pThis = new CCheckList(hWnd, (LPCREATESTRUCT)lParam);
  955. if (pThis != NULL)
  956. {
  957. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  958. lResult = TRUE;
  959. }
  960. break;
  961. case WM_DESTROY:
  962. if( pThis ) //Raid #550912, yanggao.
  963. {
  964. pThis->ResetContent(hWnd);
  965. }
  966. break;
  967. case WM_NCDESTROY:
  968. if( pThis ) //Raid #550912, yanggao.
  969. {
  970. delete pThis;
  971. }
  972. break;
  973. case WM_COMMAND:
  974. TraceAssert(pThis != NULL); //Validate pThis.
  975. if( pThis ) //Raid #550912, yanggao.
  976. {
  977. lResult = pThis->MsgCommand(hWnd,
  978. GET_WM_COMMAND_ID(wParam, lParam),
  979. GET_WM_COMMAND_CMD(wParam, lParam),
  980. GET_WM_COMMAND_HWND(wParam, lParam));
  981. }
  982. break;
  983. case WM_CTLCOLORSTATIC:
  984. TraceAssert(pThis != NULL);
  985. if( pThis ) //Raid #550912, yanggao.
  986. {
  987. break;
  988. }
  989. SetBkMode((HDC)wParam, TRANSPARENT);
  990. SetTextColor((HDC)wParam, GetSysColor(TEXT_COLOR));
  991. SetBkColor((HDC)wParam, GetSysColor(BK_COLOR));
  992. lResult = (LRESULT)GetSysColorBrush(BK_COLOR);
  993. break;
  994. case WM_PAINT:
  995. TraceAssert(pThis != NULL); //Validate pThis.
  996. if( pThis ) //Raid #550912, yanggao.
  997. {
  998. pThis->MsgPaint(hWnd, (HDC)wParam);
  999. }
  1000. break;
  1001. case WM_VSCROLL:
  1002. TraceAssert(pThis != NULL); //Validate pThis.
  1003. if( pThis ) //Raid #550912, yanggao.
  1004. {
  1005. pThis->MsgVScroll(hWnd,
  1006. (int)(short)GET_WM_VSCROLL_CODE(wParam, lParam),
  1007. (int)(short)GET_WM_VSCROLL_POS(wParam, lParam));
  1008. }
  1009. break;
  1010. case WM_MOUSEWHEEL:
  1011. TraceAssert(pThis != NULL); //Validate pThis.
  1012. if( pThis ) //Raid #550912, yanggao.
  1013. {
  1014. pThis->MsgMouseWheel(hWnd,
  1015. LOWORD(wParam),
  1016. (int)(short)HIWORD(wParam));
  1017. }
  1018. break;
  1019. case WM_LBUTTONDOWN:
  1020. TraceAssert(pThis != NULL); //Validate pThis.
  1021. if( pThis ) //Raid #550912, yanggao.
  1022. {
  1023. pThis->MsgButtonDown(hWnd,
  1024. wParam,
  1025. (int)(short)LOWORD(lParam),
  1026. (int)(short)HIWORD(lParam));
  1027. }
  1028. break;
  1029. case WM_ENABLE:
  1030. TraceAssert(pThis != NULL); //Validate pThis.
  1031. if( pThis ) //Raid #550912, yanggao.
  1032. {
  1033. pThis->MsgEnable(hWnd, (BOOL)wParam);
  1034. }
  1035. break;
  1036. case WM_SETFONT:
  1037. TraceAssert(pThis != NULL); //Validate pThis.
  1038. if( pThis ) //Raid #550912, yanggao.
  1039. {
  1040. for (LONG i = 0; i < pThis->m_cItems; i++)
  1041. SendDlgItemMessage(hWnd,
  1042. MAKE_LABEL_ID(i),
  1043. WM_SETFONT,
  1044. wParam,
  1045. lParam);
  1046. }
  1047. break;
  1048. case WM_SIZE:
  1049. TraceAssert(pThis != NULL); //Validate pThis.
  1050. if( pThis ) //Raid #550912, yanggao.
  1051. {
  1052. pThis->MsgSize(hWnd, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
  1053. }
  1054. break;
  1055. case CLM_ADDITEM:
  1056. TraceAssert(pThis != NULL); //Validate pThis.
  1057. if( pThis ) //Raid #550912, yanggao.
  1058. {
  1059. lResult = pThis->AddItem(hWnd, (LPCTSTR)wParam, lParam);
  1060. }
  1061. break;
  1062. case CLM_GETITEMCOUNT:
  1063. TraceAssert(pThis != NULL); //Validate pThis.
  1064. if( pThis ) //Raid #550912, yanggao.
  1065. {
  1066. lResult = pThis->m_cItems;
  1067. }
  1068. break;
  1069. case CLM_SETSTATE:
  1070. TraceAssert(pThis != NULL); //Validate pThis.
  1071. if( pThis ) //Raid #550912, yanggao.
  1072. {
  1073. pThis->SetState(hWnd, LOWORD(wParam), HIWORD(wParam), (LONG)lParam);
  1074. }
  1075. break;
  1076. case CLM_GETSTATE:
  1077. TraceAssert(pThis != NULL); //Validate pThis.
  1078. if( pThis ) //Raid #550912, yanggao.
  1079. {
  1080. lResult = pThis->GetState(hWnd, LOWORD(wParam), HIWORD(wParam));
  1081. }
  1082. break;
  1083. case CLM_SETCOLUMNWIDTH:
  1084. TraceAssert(pThis != NULL); //Validate pThis.
  1085. if( pThis ) //Raid #550912, yanggao.
  1086. {
  1087. RECT rc;
  1088. LONG cxDialog;
  1089. GetClientRect(hWnd, &rc);
  1090. cxDialog = rc.right;
  1091. rc.right = (LONG)lParam;
  1092. MapDialogRect(GetParent(hWnd), &rc);
  1093. pThis->SetColumnWidth(hWnd, cxDialog, rc.right);
  1094. }
  1095. break;
  1096. case CLM_SETITEMDATA:
  1097. TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems); //Validate pThis and the expression.
  1098. if( !pThis || !(GET_ITEM(wParam) < (ULONG)pThis->m_cItems) ) //Raid #550912, yanggao.
  1099. {
  1100. break;
  1101. }
  1102. pUserData = (LPUSERDATA_STRUCT_LABEL)
  1103. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1104. GWLP_USERDATA);
  1105. if (pUserData != NULL)
  1106. pUserData->lParam = lParam;
  1107. break;
  1108. case CLM_GETITEMDATA:
  1109. TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems); //Validate pThis and the expression.
  1110. if( !pThis || !(GET_ITEM(wParam) < (ULONG)pThis->m_cItems) ) //Raid #550912, yanggao.
  1111. {
  1112. break;
  1113. }
  1114. pUserData = (LPUSERDATA_STRUCT_LABEL)
  1115. GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
  1116. GWLP_USERDATA);
  1117. if (pUserData != NULL)
  1118. lResult = pUserData->lParam;
  1119. break;
  1120. case CLM_RESETCONTENT:
  1121. TraceAssert(pThis != NULL); //Validate pThis.
  1122. if( pThis ) //Raid #550912, yanggao.
  1123. {
  1124. pThis->ResetContent(hWnd);
  1125. }
  1126. break;
  1127. case CLM_GETVISIBLECOUNT:
  1128. TraceAssert(pThis != NULL); //Validate pThis.
  1129. if( pThis ) //Raid #550912, yanggao.
  1130. {
  1131. lResult = pThis->GetVisibleCount(hWnd);
  1132. }
  1133. break;
  1134. case CLM_GETTOPINDEX:
  1135. TraceAssert(pThis != NULL); //Validate pThis.
  1136. if( pThis ) //Raid #550912, yanggao.
  1137. {
  1138. lResult = pThis->GetTopIndex(hWnd);
  1139. }
  1140. break;
  1141. case CLM_SETTOPINDEX:
  1142. TraceAssert(pThis != NULL); //Validate pThis.
  1143. if( pThis ) //Raid #550912, yanggao.
  1144. {
  1145. pThis->SetTopIndex(hWnd, (LONG)wParam);
  1146. }
  1147. break;
  1148. case CLM_ENSUREVISIBLE:
  1149. TraceAssert(pThis != NULL); //Validate pThis.
  1150. if( pThis ) //Raid #550912, yanggao.
  1151. {
  1152. pThis->EnsureVisible(hWnd, (LONG)wParam);
  1153. }
  1154. break;
  1155. //
  1156. // Always refer to the chklist window for help. Don't pass
  1157. // one of the child window handles here.
  1158. //
  1159. case WM_HELP:
  1160. ((LPHELPINFO)lParam)->hItemHandle = hWnd;
  1161. lResult = SendMessage(GetParent(hWnd), uMsg, wParam, lParam);
  1162. break;
  1163. case WM_CONTEXTMENU:
  1164. lResult = SendMessage(GetParent(hWnd), uMsg, (WPARAM)hWnd, lParam);
  1165. break;
  1166. case WM_SETCURSOR:
  1167. if (LOWORD(lParam) == HTCLIENT)
  1168. {
  1169. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1170. lResult = TRUE;
  1171. break;
  1172. }
  1173. // Fall Through
  1174. default:
  1175. lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
  1176. }
  1177. TraceLeaveValue(lResult);
  1178. }