Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1997 lines
56 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. Clb.c
  5. Abstract:
  6. This file contains support for the ColumnListBox (clb.dll) custom control.
  7. Author:
  8. David J. Gilman (davegi) 05-Feb-1993
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "clb.h"
  13. #include <commctrl.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <tchar.h>
  18. //
  19. // Clb's module handle.
  20. //
  21. HINSTANCE
  22. _hModule;
  23. //
  24. // Child IDs for the header and listbox controls.
  25. //
  26. #define ID_HEADER ( 0x1234 )
  27. #define ID_LISTBOX ( 0xABCD )
  28. //
  29. // Separator used to parse headings.
  30. //
  31. #define HEADING_SEPARATOR L";"
  32. //
  33. // Valid styles for each part of the Clb.
  34. //
  35. #define CLBS_CLB ( \
  36. 0 \
  37. | CLBS_BORDER \
  38. | LBS_OWNERDRAWFIXED \
  39. | WS_VISIBLE \
  40. | WS_DISABLED \
  41. | WS_GROUP \
  42. | WS_TABSTOP \
  43. | WS_CHILD \
  44. )
  45. #define CLBS_HEADER ( \
  46. 0 \
  47. | WS_VISIBLE \
  48. | CLBS_POPOUT_HEADINGS \
  49. | CLBS_SPRINGY_COLUMNS \
  50. )
  51. #define CLBS_LIST_BOX ( \
  52. 0 \
  53. | WS_VISIBLE \
  54. | CLBS_NOTIFY \
  55. | CLBS_SORT \
  56. | CLBS_DISABLENOSCROLL \
  57. | CLBS_VSCROLL \
  58. )
  59. //
  60. // Window procedure for the CLB.
  61. //
  62. LRESULT
  63. ClbWndProc(
  64. IN HWND hWnd,
  65. IN UINT message,
  66. IN WPARAM wParam,
  67. IN LPARAM lParam
  68. );
  69. //
  70. // Per CLB window information.
  71. //
  72. // hWndHeader - hWnd for header control.
  73. // hWndListBox - hWnd for listbox control.
  74. // hFontListBox - hFont for the list box control.
  75. // HeaderHeight - height of the header window.
  76. // Columns - number of columns in CLB.
  77. // Headings - raw (semi-colon separated) column headings.
  78. // Right - array of right edge coordinates.
  79. //
  80. typedef
  81. struct
  82. _CLB_INFO {
  83. DECLARE_SIGNATURE
  84. HWND hWndHeader;
  85. HWND hWndListBox;
  86. HFONT hFontListBox;
  87. DWORD HeaderHeight;
  88. DWORD Columns;
  89. WCHAR Headings[ MAX_PATH ];
  90. LPLONG Right;
  91. } CLB_INFO, *LPCLB_INFO;
  92. //
  93. // Helper macros to save and restore per Clb window information.
  94. //
  95. #define SaveClbInfo( p ) \
  96. SetWindowLongPtr( hWnd, 0, ( LONG_PTR )( p ))
  97. #define RestoreClbInfo( h ) \
  98. ( LPCLB_INFO ) GetWindowLongPtr(( h ), 0 )
  99. //
  100. // Structures to support drawing and ersaing the drag line.
  101. //
  102. typedef
  103. struct
  104. _LINE_POINTS {
  105. POINT Src;
  106. POINT Dst;
  107. } LINE_POINT, *LPLINE_POINT;
  108. typedef
  109. struct
  110. _DRAW_ERASE_LINE {
  111. LINE_POINT Erase;
  112. LINE_POINT Draw;
  113. } DRAW_ERASE_LINE, *LPDRAW_ERASE_LINE;
  114. BOOL
  115. DrawLine(
  116. IN HDC hDC,
  117. IN LPDRAW_ERASE_LINE DrawEraseLine
  118. )
  119. /*++
  120. Routine Description:
  121. DrawLine draws the Draw line in the supplied DrawEraseLine structure
  122. and then sets up that line so that EraseLine will erase it.
  123. Arguments:
  124. hDC - Supplies a handle to the DC where the line should be
  125. drawn.
  126. DrawEraseLine - Supplies a pointer to a DRAW_ERASE_LINE structure that
  127. conatins the coordinates for the line to be drawn.
  128. Return Value:
  129. BOOL - Returns TRUE if the line was succesfully drawn.
  130. --*/
  131. {
  132. BOOL Success;
  133. DbgHandleAssert( hDC );
  134. DbgPointerAssert( DrawEraseLine );
  135. Success = Polyline( hDC, ( CONST LPPOINT ) &DrawEraseLine->Draw, 2 );
  136. DbgAssert( Success );
  137. DrawEraseLine->Erase = DrawEraseLine->Draw;
  138. return Success;
  139. }
  140. BOOL
  141. EraseLine(
  142. IN HDC hDC,
  143. IN LPDRAW_ERASE_LINE DrawEraseLine
  144. )
  145. /*++
  146. Routine Description:
  147. EraseLine erasess the Erase line in the supplied DrawEraseLine structure.
  148. The EraseLine is set by the DrawLine routine.
  149. Arguments:
  150. hDC - Supplies a handle to the DC where the line should
  151. be erased.
  152. DrawEraseLine - Supplies a pointer to a DRAW_ERASE_LINE structure that
  153. conatins the coordinates for the line to be erased.
  154. Return Value:
  155. BOOL - Returns TRUE if the line was succesfully erased.
  156. --*/
  157. {
  158. BOOL Success;
  159. DbgHandleAssert( hDC );
  160. DbgPointerAssert( DrawEraseLine );
  161. Success = Polyline( hDC, ( CONST LPPOINT ) &DrawEraseLine->Erase, 2 );
  162. DbgAssert( Success );
  163. return Success;
  164. }
  165. BOOL
  166. RedrawVerticalLine(
  167. IN HDC hDC,
  168. IN LONG x,
  169. IN LPDRAW_ERASE_LINE DrawEraseLine
  170. )
  171. /*++
  172. Routine Description:
  173. RedrawVerticalLine erases the old line and redraws a new one at the
  174. supplied x position. It is merely a warpper for DrawLine and EraseLine.
  175. Arguments:
  176. hDC - Supplies a handle to the DC where the line should
  177. be erased.
  178. x - Supplies the new x coordinate where the line should
  179. be drawn.
  180. DrawEraseLine - Supplies a pointer to a DRAW_ERASE_LINE structure that
  181. conatins the coordinates for the line to be erased.
  182. Return Value:
  183. BOOL - Returns TRUE if the line was succesfully erased.
  184. --*/
  185. {
  186. BOOL Success;
  187. DbgHandleAssert( hDC );
  188. DbgPointerAssert( DrawEraseLine );
  189. DrawEraseLine->Draw.Src.x = x;
  190. DrawEraseLine->Draw.Dst.x = x;
  191. Success = EraseLine( hDC, DrawEraseLine );
  192. DbgAssert( Success );
  193. Success = DrawLine( hDC, DrawEraseLine );
  194. DbgAssert( Success );
  195. return Success;
  196. }
  197. BOOL
  198. ClbEntryPoint(
  199. IN HINSTANCE hInstanceDll,
  200. IN DWORD Reason,
  201. IN LPVOID Reserved
  202. )
  203. /*++
  204. Routine Description:
  205. This function registers the ColumndListBox class as a global class for
  206. any process that attaches to clb.dll.
  207. Arguments:
  208. Standard DLL entry parameters.
  209. Return Value:
  210. BOOL - Returns TRUE if the class was succesfully registered.
  211. --*/
  212. {
  213. BOOL Success;
  214. static
  215. DWORD AttachedProcesses = 0;
  216. switch ( Reason ) {
  217. case DLL_PROCESS_ATTACH:
  218. {
  219. WNDCLASS Wc;
  220. ATOM Class;
  221. //
  222. // If this is the first process attaching to Clb, register the
  223. // window class.
  224. //
  225. if ( AttachedProcesses == 0 ) {
  226. //
  227. // Remember the module handle.
  228. //
  229. _hModule = hInstanceDll;
  230. //
  231. // Make sure that the Common Controls (comctl32.dll) Dll
  232. // is loaded.
  233. //
  234. InitCommonControls( );
  235. Wc.style = CS_GLOBALCLASS
  236. | CS_OWNDC;
  237. Wc.lpfnWndProc = ClbWndProc;
  238. Wc.cbClsExtra = 0;
  239. Wc.cbWndExtra = sizeof( LPCLB_INFO );
  240. Wc.hInstance = hInstanceDll;
  241. Wc.hIcon = NULL;
  242. Wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  243. Wc.hbrBackground = NULL;
  244. Wc.lpszMenuName = NULL;
  245. Wc.lpszClassName = CLB_CLASS_NAME;
  246. //
  247. // If the class couldn't be registered, fail the linkage.
  248. //
  249. Class = RegisterClass( &Wc );
  250. DbgAssert( Class != 0 );
  251. if ( Class == 0 ) {
  252. return FALSE;
  253. }
  254. }
  255. //
  256. // Either the class was just succesfully registered or it was
  257. // registered by a prior process attachment, eother way increment
  258. // the count of attached processes.
  259. //
  260. AttachedProcesses++;
  261. return TRUE;
  262. }
  263. case DLL_PROCESS_DETACH:
  264. {
  265. DbgAssert( AttachedProcesses > 0 );
  266. AttachedProcesses--;
  267. if ( AttachedProcesses == 0 ) {
  268. Success = UnregisterClass( CLB_CLASS_NAME, hInstanceDll );
  269. DbgAssert( Success );
  270. }
  271. break;
  272. }
  273. }
  274. return TRUE;
  275. }
  276. BOOL
  277. ClbAddData(
  278. IN HWND hWnd,
  279. IN int ControlId,
  280. IN LPCLB_ROW ClbRow
  281. )
  282. /*++
  283. Routine Description:
  284. ClbAddData adds a new row of data to the Clb control's List Box.
  285. Arguments:
  286. hWnd - Supplies the window handle for the parent window.
  287. ControlId - Supplies the control id for this Clb for the supplied hWnd.
  288. ClbRow - Supplies a pointer to a CLB_ROW object which contains user
  289. define per row data along with an array of CLB_STRINGs.
  290. Return Value:
  291. BOOL - Returns TRUE if the data was successfully added.
  292. --*/
  293. {
  294. LPCLB_INFO ClbInfo;
  295. LRESULT LbErr;
  296. DWORD i;
  297. HWND hWndClb;
  298. LPCLB_ROW TempRow;
  299. //
  300. // Validate arguments.
  301. //
  302. DbgHandleAssert( hWnd );
  303. DbgPointerAssert( ClbRow );
  304. //
  305. // Retrieve information for this ColumnListBox.
  306. //
  307. hWndClb = GetDlgItem( hWnd, ControlId );
  308. DbgHandleAssert( hWndClb );
  309. if (hWndClb == NULL)
  310. return FALSE;
  311. ClbInfo = RestoreClbInfo( hWndClb );
  312. DbgPointerAssert( ClbInfo );
  313. if (ClbInfo == NULL)
  314. return FALSE;
  315. DbgAssert( CheckSignature( ClbInfo ));
  316. //
  317. // Validate the count of strings.
  318. //
  319. DbgAssert( ClbRow->Count == ClbInfo->Columns );
  320. //
  321. // Capture the CLB_ROW object.
  322. //
  323. TempRow = AllocateObject( CLB_ROW, 1 );
  324. DbgPointerAssert( TempRow );
  325. if (TempRow == NULL)
  326. return FALSE;
  327. CopyMemory(
  328. TempRow,
  329. ClbRow,
  330. sizeof( CLB_ROW)
  331. );
  332. //
  333. // Capture the strings.
  334. //
  335. TempRow->Strings = AllocateObject( CLB_STRING, ClbInfo->Columns );
  336. DbgPointerAssert( TempRow->Strings );
  337. if (TempRow->Strings == NULL)
  338. return FALSE;
  339. for ( i = 0; i < ClbInfo->Columns; i++ ) {
  340. //
  341. // Copy the header.
  342. //
  343. CopyMemory(
  344. &TempRow->Strings[ i ],
  345. &ClbRow->Strings[ i ],
  346. sizeof( CLB_STRING )
  347. );
  348. //
  349. // Copy the string.
  350. //
  351. TempRow->Strings[ i ].String = _wcsdup( ClbRow->Strings[ i ].String );
  352. }
  353. //
  354. // Store the CLB_ROW object in the listbox.
  355. //
  356. LbErr = SendMessage(
  357. ClbInfo->hWndListBox,
  358. LB_ADDSTRING,
  359. 0,
  360. ( LPARAM ) TempRow
  361. );
  362. DbgAssert(( LbErr != LB_ERR ) && ( LbErr != LB_ERRSPACE ));
  363. return TRUE;
  364. }
  365. BOOL
  366. ClbSetColumnWidths(
  367. IN HWND hWnd,
  368. IN int ControlId,
  369. IN LPDWORD Widths
  370. )
  371. /*++
  372. Routine Description:
  373. ClbSetColumnWidths sets the width of each column based on the supplied
  374. widths in characters. Note that the column on the far right extends to
  375. the edge of the Clb.
  376. Arguments:
  377. hWnd - Supplies the window handle for the parent window.
  378. ControlId - Supplies the control id for this Clb for the supplied hWnd.
  379. Widths - Supplies an array of widths, one less then the number of
  380. columns, in characters.
  381. Return Value:
  382. BOOL - Returns TRUE if the widths were successfully adjusted.
  383. --*/
  384. {
  385. BOOL Success;
  386. DWORD Columns;
  387. LPCLB_INFO ClbInfo;
  388. HWND hWndClb;
  389. LONG CharWidth;
  390. LONG CharHeight;
  391. DWORD i;
  392. LPLONG WidthsInPixels;
  393. LONG TotalPixels;
  394. HDC hDCClientHeader;
  395. HD_ITEM hdi;
  396. UINT iRight;
  397. //
  398. // Validate arguments.
  399. //
  400. DbgHandleAssert( hWnd );
  401. DbgPointerAssert( Widths );
  402. //
  403. // Retrieve information for this ColumnListBox.
  404. //
  405. hWndClb = GetDlgItem( hWnd, ControlId );
  406. DbgHandleAssert( hWndClb );
  407. if (hWndClb == NULL)
  408. return FALSE;
  409. ClbInfo = RestoreClbInfo( hWndClb );
  410. DbgPointerAssert( ClbInfo );
  411. if (ClbInfo == NULL)
  412. return FALSE;
  413. DbgAssert( CheckSignature( ClbInfo ));
  414. //
  415. // Get thd HDC for the header.
  416. //
  417. hDCClientHeader = GetDC( ClbInfo->hWndHeader );
  418. DbgHandleAssert( hDCClientHeader );
  419. if (hDCClientHeader == NULL)
  420. return FALSE;
  421. //
  422. // Get the width of a character.
  423. //
  424. Success = GetCharMetrics(
  425. hDCClientHeader,
  426. &CharWidth,
  427. &CharHeight
  428. );
  429. DbgAssert( Success );
  430. //
  431. // Release the DC for the header.
  432. //
  433. Success = ReleaseDC( ClbInfo->hWndHeader, hDCClientHeader );
  434. DbgAssert( Success );
  435. //
  436. // Allocate an array of pixel widths, one for each column.
  437. //
  438. WidthsInPixels = AllocateObject( LONG, ClbInfo->Columns );
  439. DbgPointerAssert( WidthsInPixels );
  440. if (WidthsInPixels == NULL)
  441. return FALSE;
  442. //
  443. // Compute the width of each column (not including the rightmost) in pixels,
  444. // and the total number of pixels used by these columns.
  445. //
  446. TotalPixels = 0;
  447. for ( i = 0; i < ClbInfo->Columns - 1; i++ ) {
  448. WidthsInPixels[ i ] = Widths[ i ] * CharWidth;
  449. TotalPixels += WidthsInPixels[ i ];
  450. }
  451. //
  452. // The caller did not specify the width of the rightmost column.
  453. //
  454. if ( Widths[ i ] == -1 ) {
  455. RECT Rect;
  456. //
  457. // Set the width of the rightmost column to the remainder of the width
  458. // of the header window.
  459. //
  460. Success = GetClientRect(
  461. ClbInfo->hWndHeader,
  462. &Rect
  463. );
  464. DbgAssert( Success );
  465. WidthsInPixels[ i ] = ( Rect.right - Rect.left ) - TotalPixels;
  466. } else {
  467. //
  468. // Set the width of the rightmost column to the value supplied
  469. // by the caller.
  470. //
  471. WidthsInPixels[ i ] = Widths[ i ] * CharWidth;
  472. }
  473. //
  474. // Tell the header window the width of each column.
  475. //
  476. hdi.mask = HDI_WIDTH;
  477. for ( i = 0; i < ClbInfo->Columns - 1; i++ ) {
  478. hdi.cxy = WidthsInPixels[i];
  479. Success = Header_SetItem(ClbInfo->hWndHeader, i, &hdi);
  480. DbgAssert( Success );
  481. }
  482. //
  483. // Calc the array of right edges.
  484. //
  485. iRight = 0;
  486. for ( i = 0; i < ClbInfo->Columns - 1; i++ ) {
  487. iRight += WidthsInPixels[i];
  488. ClbInfo->Right[i] = iRight;
  489. }
  490. //
  491. // Free the array of pixel widths.
  492. //
  493. Success = FreeObject( WidthsInPixels );
  494. DbgAssert( Success );
  495. return TRUE;
  496. }
  497. BOOL
  498. AdjustClbHeadings(
  499. IN HWND hWnd,
  500. IN LPCLB_INFO ClbInfo,
  501. IN LPCWSTR Headings OPTIONAL
  502. )
  503. /*++
  504. Routine Description:
  505. AdjustClbHeadings adjust the number of columns, the widths an header text
  506. bbased on the optional Headings parameter. If Headings is NULL then the
  507. column widths are adjusted based on the old headings and the current size
  508. of the Clb. If Headings are supplied then they consist of ';' separated
  509. strings, each of which is a column heading. The number of columns and their
  510. widths is then computed based on these new headings.
  511. Arguments:
  512. hWnd - Supplies a window handle for this Clb.
  513. ClbInfo - Supplies a pointer the CLB_INFO structure for this Clb.
  514. Headings - Supplies an optional pointer to a ';' separated series of
  515. column header strings.
  516. Return Value:
  517. BOOL - Returns TRUE if the adjustment was succesfully made.
  518. --*/
  519. {
  520. BOOL Success;
  521. DWORD Columns;
  522. DWORD ColumnWidth;
  523. DWORD i;
  524. TCHAR Buffer[ MAX_PATH ];
  525. LPCWSTR Heading;
  526. RECT ClientRectHeader;
  527. HD_ITEM hdi;
  528. UINT iCount, j, iRight;
  529. DbgPointerAssert( ClbInfo );
  530. DbgAssert( ! (( ClbInfo->Columns == 0 ) && ( Headings == NULL )));
  531. //
  532. // If the user supplied headings, compute the new number of columns.
  533. //
  534. if ( ARGUMENT_PRESENT( Headings )) {
  535. //
  536. // Initialize the column counter.
  537. //
  538. Columns = 0;
  539. //
  540. // Make a copy of the new headings in the Clb object.
  541. //
  542. lstrcpy( ClbInfo->Headings, Headings );
  543. //
  544. // Make a copy of the heading string so that it can be tokenized.
  545. // i.e. wcstok destroys the string.
  546. //
  547. lstrcpy( Buffer, Headings );
  548. //
  549. // Grab the first token (heading).
  550. //
  551. Heading = _tcstok( Buffer, HEADING_SEPARATOR );
  552. //
  553. // For each heading...
  554. //
  555. while ( Heading != NULL ) {
  556. //
  557. // Increment the number of columns.
  558. //
  559. Columns++;
  560. //
  561. // Get the next heading.
  562. //
  563. Heading = _tcstok( NULL, HEADING_SEPARATOR );
  564. }
  565. } else {
  566. //
  567. // Same number of Columns as before.
  568. //
  569. Columns = ClbInfo->Columns;
  570. }
  571. //
  572. // If the number of columns in the Clb is zero (i.e. this is the first
  573. // time it is being initialized) allocate the right edge array. Otherwise
  574. // reallocate the existing array if the number of columns has changed.
  575. //
  576. if ( ClbInfo->Columns == 0 ) {
  577. ClbInfo->Right = AllocateObject( LONG, Columns );
  578. DbgPointerAssert( ClbInfo->Right );
  579. } else if ( Columns != ClbInfo->Columns ) {
  580. ClbInfo->Right = ReallocateObject( LONG, ClbInfo->Right, Columns );
  581. DbgPointerAssert( ClbInfo->Right );
  582. }
  583. if (ClbInfo->Right == NULL)
  584. return FALSE;
  585. //
  586. // Update the number of columns in the Clb (note this may be the same
  587. // number as before).
  588. //
  589. ClbInfo->Columns = Columns;
  590. //
  591. // Compute the default column width by dividing the available space by the
  592. // number of columns.
  593. //
  594. Success = GetClientRect( ClbInfo->hWndHeader, &ClientRectHeader );
  595. DbgAssert( Success );
  596. ColumnWidth = ( ClientRectHeader.right - ClientRectHeader.left )
  597. / ClbInfo->Columns;
  598. //
  599. // Initialize the array of right edges to the width of each column.
  600. //
  601. for ( i = 0; i < ClbInfo->Columns; i++ ) {
  602. ClbInfo->Right[ i ] = ColumnWidth;
  603. }
  604. //
  605. // Update the existing header items
  606. //
  607. iCount = Header_GetItemCount(ClbInfo->hWndHeader);
  608. j = 0;
  609. hdi.mask = HDI_WIDTH;
  610. while ((j < iCount) && (j < Columns)) {
  611. hdi.cxy = ClbInfo->Right[j];
  612. Header_SetItem (ClbInfo->hWndHeader, j, &hdi);
  613. j++;
  614. }
  615. //
  616. // Add new header items if necessary.
  617. //
  618. hdi.mask = HDI_WIDTH;
  619. for (; j < Columns; j++) {
  620. hdi.cxy = ClbInfo->Right[j];
  621. Header_InsertItem (ClbInfo->hWndHeader, j, &hdi);
  622. }
  623. //
  624. // Query the header for the array of right edges.
  625. //
  626. iRight = 0;
  627. for ( i = 0; i < ClbInfo->Columns - 1; i++ ) {
  628. iRight += ClbInfo->Right[i];
  629. ClbInfo->Right[i] = iRight;
  630. }
  631. ClbInfo->Right[i] = ClientRectHeader.right;
  632. //
  633. // Copy and parse the headings so that each column's heading
  634. // can be set. These can be new or old headings.
  635. //
  636. lstrcpy( Buffer, ClbInfo->Headings );
  637. Heading = _tcstok( Buffer, HEADING_SEPARATOR );
  638. hdi.mask = HDI_TEXT | HDI_FORMAT;
  639. hdi.fmt = HDF_STRING;
  640. for ( i = 0; i < ClbInfo->Columns; i++ ) {
  641. hdi.pszText = (LPTSTR)Heading;
  642. Header_SetItem (ClbInfo->hWndHeader, i, &hdi);
  643. Heading = _tcstok( NULL, HEADING_SEPARATOR );
  644. }
  645. return TRUE;
  646. }
  647. BOOL
  648. CreateHeader(
  649. IN HWND hWnd,
  650. IN LPCLB_INFO ClbInfo,
  651. IN LPCREATESTRUCT lpcs
  652. )
  653. /*++
  654. Routine Description:
  655. Create the header portion of the Clb.
  656. Arguments:
  657. hWnd - Supplies a window handle for the parent (i.e. Clb) window.
  658. ClbInfo - Supplies a pointer the CLB_INFO structure for this Clb.
  659. lpcs - Supplies a pointer to a CREATESTRUCT structure.
  660. Return Value:
  661. BOOL - Returns TRUE if the header portion of the Clb was
  662. succesfully created.
  663. --*/
  664. {
  665. BOOL Success;
  666. RECT WindowRectHeader, rcParent;
  667. HD_LAYOUT hdl;
  668. WINDOWPOS wp;
  669. DbgHandleAssert( hWnd );
  670. DbgPointerAssert( ClbInfo );
  671. DbgPointerAssert( lpcs );
  672. //
  673. // Create the header window using the appropriate supplied styles,
  674. // augmented by additional styles needed by Clb, relative to the upper
  675. // left corner of the Clb and with a default height.
  676. // The width is adjusted in the WM_SIZE message handler.
  677. //
  678. ClbInfo->hWndHeader = CreateWindow(
  679. WC_HEADER,
  680. NULL,
  681. (
  682. lpcs->style
  683. & CLBS_HEADER
  684. )
  685. | WS_CHILD,
  686. 0,
  687. 0,
  688. 0,
  689. CW_USEDEFAULT,
  690. hWnd,
  691. ( HMENU ) ID_HEADER,
  692. NULL,
  693. NULL
  694. );
  695. DbgHandleAssert( ClbInfo->hWndHeader );
  696. if (ClbInfo->hWndHeader == NULL)
  697. return FALSE;
  698. //
  699. // Compute and save the height of the header window. This is used to
  700. // position the list box.
  701. //
  702. GetClientRect(hWnd, &rcParent);
  703. hdl.prc = &rcParent;
  704. hdl.pwpos = &wp;
  705. SendMessage(ClbInfo->hWndHeader, HDM_LAYOUT, 0, (LPARAM)&hdl);
  706. SetWindowPos(ClbInfo->hWndHeader, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy,
  707. wp.flags);
  708. ClbInfo->HeaderHeight = wp.cy;
  709. return TRUE;
  710. }
  711. BOOL
  712. CreateListBox(
  713. IN HWND hWnd,
  714. IN LPCLB_INFO ClbInfo,
  715. IN LPCREATESTRUCT lpcs
  716. )
  717. /*++
  718. Routine Description:
  719. Create the list box portion of the Clb.
  720. Arguments:
  721. hWnd - Supplies a window handle for the parent (i.e. Clb) window.
  722. ClbInfo - Supplies a pointer the CLB_INFO structure for this Clb.
  723. lpcs - Supplies a pointer to a CREATESTRUCT structure.
  724. Return Value:
  725. BOOL - Returns TRUE if the list box portion of the Clb was
  726. succesfully created.
  727. --*/
  728. {
  729. BOOL Success;
  730. LOGFONT LogFont;
  731. HDC hDCClientListBox;
  732. CHARSETINFO csi;
  733. DWORD dw = GetACP();
  734. if (!TranslateCharsetInfo(&dw, &csi, TCI_SRCCODEPAGE))
  735. csi.ciCharset = ANSI_CHARSET;
  736. DbgHandleAssert( hWnd );
  737. DbgPointerAssert( ClbInfo );
  738. DbgPointerAssert( lpcs );
  739. //
  740. //
  741. // Create the list box using the appropriate supplied styles,
  742. // augmented by additional styles needed by Clb, relative to the lower left
  743. // corner of the header window plus one. This additional row is reserved so
  744. // that a border can be drawn between the header and the list box. The size
  745. // is adjusted in the WM_SIZE message handler.
  746. //
  747. ClbInfo->hWndListBox = CreateWindow(
  748. L"LISTBOX",
  749. NULL,
  750. (
  751. lpcs->style
  752. & CLBS_LIST_BOX
  753. )
  754. | LBS_NOINTEGRALHEIGHT
  755. | LBS_OWNERDRAWFIXED
  756. | WS_CHILD,
  757. 0,
  758. ClbInfo->HeaderHeight + 3,
  759. 0,
  760. 0,
  761. hWnd,
  762. ( HMENU ) ID_LISTBOX,
  763. NULL,
  764. NULL
  765. );
  766. DbgHandleAssert( ClbInfo->hWndListBox );
  767. if (ClbInfo->hWndListBox == NULL)
  768. return FALSE;
  769. //
  770. // Get thd HDC for the list box.
  771. //
  772. hDCClientListBox = GetDC( ClbInfo->hWndListBox );
  773. DbgHandleAssert( hDCClientListBox );
  774. if (hDCClientListBox == NULL)
  775. return FALSE;
  776. //
  777. // Set the default font for the list box to MS Shell Dlg.
  778. //
  779. LogFont.lfHeight = MulDiv(
  780. -9,
  781. GetDeviceCaps(
  782. hDCClientListBox,
  783. LOGPIXELSY
  784. )
  785. ,72
  786. );
  787. LogFont.lfWidth = 0;
  788. LogFont.lfEscapement = 0;
  789. LogFont.lfOrientation = 0;
  790. LogFont.lfWeight = FW_NORMAL;
  791. LogFont.lfItalic = FALSE;
  792. LogFont.lfUnderline = FALSE;
  793. LogFont.lfStrikeOut = FALSE;
  794. LogFont.lfCharSet = (BYTE)csi.ciCharset;
  795. LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  796. LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  797. LogFont.lfQuality = DEFAULT_QUALITY;
  798. LogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  799. _tcscpy( LogFont.lfFaceName, TEXT( "MS Shell Dlg" ));
  800. ClbInfo->hFontListBox = CreateFontIndirect( &LogFont );
  801. DbgHandleAssert( ClbInfo->hFontListBox );
  802. if (ClbInfo->hFontListBox == NULL)
  803. return FALSE;
  804. SendMessage(
  805. ClbInfo->hWndListBox,
  806. WM_SETFONT,
  807. ( WPARAM ) ClbInfo->hFontListBox,
  808. MAKELPARAM( FALSE, 0 )
  809. );
  810. //
  811. // Release the DC for the list box.
  812. //
  813. Success = ReleaseDC( ClbInfo->hWndListBox, hDCClientListBox );
  814. DbgAssert( Success );
  815. return TRUE;
  816. }
  817. LRESULT
  818. ClbWndProc(
  819. IN HWND hWnd,
  820. IN UINT message,
  821. IN WPARAM wParam,
  822. IN LPARAM lParam
  823. )
  824. /*++
  825. Routine Description:
  826. This function is the window procedure for the Clb custom control.
  827. Arguments:
  828. Standard window procedure parameters.
  829. Return Value:
  830. LRESULT - dependent on the supplied message.
  831. --*/
  832. {
  833. BOOL Success;
  834. LPCLB_INFO ClbInfo;
  835. if ( message == WM_NCCREATE ) {
  836. LONG Long;
  837. //
  838. // Save the original styles.
  839. //
  840. Long = SetWindowLong(hWnd, GWLP_USERDATA,(( LPCREATESTRUCT ) lParam )->style);
  841. DbgAssert( Long == 0 );
  842. //
  843. // Get rid of any styles that are uninteresting to the Clb.
  844. //
  845. SetWindowLong(
  846. hWnd,
  847. GWL_STYLE,
  848. (( LPCREATESTRUCT ) lParam )->style
  849. & CLBS_CLB
  850. );
  851. return TRUE;
  852. }
  853. if ( message == WM_CREATE ) {
  854. //
  855. // Assert that there is no prior per window information associated
  856. // with this Clb.
  857. //
  858. DbgAssert( RestoreClbInfo( hWnd ) == NULL );
  859. //
  860. // Restore the original styles.
  861. //
  862. (( LPCREATESTRUCT ) lParam )->style = GetWindowLong(
  863. hWnd,
  864. GWLP_USERDATA
  865. );
  866. //
  867. // Allocate a CLB_INFO object for this Clb and initialize the Clb
  868. // relevant fields.
  869. //
  870. ClbInfo = AllocateObject( CLB_INFO, 1 );
  871. DbgPointerAssert( ClbInfo );
  872. if (ClbInfo == NULL)
  873. return FALSE;
  874. //
  875. // Set the number of columns to zero so that remainder of creation
  876. // understands the state of the Clb.
  877. //
  878. ClbInfo->Columns = 0;
  879. //
  880. // Create the header portion of the Clb.
  881. //
  882. Success = CreateHeader( hWnd, ClbInfo, ( LPCREATESTRUCT ) lParam );
  883. DbgAssert( Success );
  884. //
  885. // Create the list box portion of the Clb.
  886. //
  887. Success = CreateListBox( hWnd, ClbInfo, ( LPCREATESTRUCT ) lParam );
  888. DbgAssert( Success );
  889. //
  890. // Adjust the column number, widths based on the heading text.
  891. //
  892. Success = AdjustClbHeadings( hWnd, ClbInfo, (( LPCREATESTRUCT ) lParam )->lpszName );
  893. DbgAssert( Success );
  894. //
  895. // Everything was succesfully created so set the Clb's signature
  896. // and save it away as part of the per window data.
  897. //
  898. SetSignature( ClbInfo );
  899. SaveClbInfo( ClbInfo );
  900. return 0;
  901. }
  902. //
  903. // Get the ClbInfo object for this Clb and make sure that its already
  904. // been created i.e. WM_CREATE was already executed and thereby initialized
  905. // and saved a ClbInfo object.
  906. //
  907. ClbInfo = RestoreClbInfo( hWnd );
  908. if ( ClbInfo != NULL ) {
  909. //
  910. // Validate that this really is a ClbInfo object.
  911. //
  912. DbgAssert( CheckSignature( ClbInfo ));
  913. switch ( message ) {
  914. case WM_DESTROY:
  915. {
  916. //
  917. // Delete the font used in the list box.
  918. //
  919. Success = DeleteObject( ClbInfo->hFontListBox );
  920. DbgAssert( Success );
  921. //
  922. // Delete the array of right habd edges.
  923. //
  924. Success = FreeObject( ClbInfo->Right );
  925. DbgAssert( Success );
  926. //
  927. // Delete the CLB_INFO object for this window.
  928. //
  929. Success = FreeObject( ClbInfo );
  930. DbgAssert( Success );
  931. SaveClbInfo ( ClbInfo );
  932. return 0;
  933. }
  934. case WM_PAINT:
  935. {
  936. PAINTSTRUCT ps;
  937. RECT Rect;
  938. POINT Points[ 2 ];
  939. HDC hDC;
  940. HPEN hPen;
  941. hDC = BeginPaint( hWnd, &ps );
  942. DbgAssert( hDC == ps.hdc );
  943. Success = GetClientRect( hWnd, &Rect );
  944. DbgAssert( Success );
  945. Points[ 0 ].x = 0;
  946. Points[ 0 ].y = ClbInfo->HeaderHeight + 1;
  947. Points[ 1 ].x = Rect.right - Rect.left;
  948. Points[ 1 ].y = ClbInfo->HeaderHeight + 1;
  949. hPen = GetStockObject( BLACK_PEN );
  950. DbgHandleAssert( hPen );
  951. hPen = SelectObject( hDC, hPen );
  952. Success = Polyline( hDC, Points, NumberOfEntries( Points ));
  953. DbgAssert( Success );
  954. hPen = SelectObject( hDC, hPen );
  955. if (hPen) {
  956. Success = DeleteObject( hPen );
  957. DbgAssert( Success );
  958. }
  959. Success = EndPaint( hWnd, &ps );
  960. DbgAssert( Success );
  961. return 0;
  962. }
  963. case WM_COMMAND:
  964. switch ( LOWORD( wParam )) {
  965. case ID_LISTBOX:
  966. switch ( HIWORD( wParam )) {
  967. case LBN_DBLCLK:
  968. case LBN_KILLFOCUS:
  969. case LBN_SELCHANGE:
  970. {
  971. //
  972. // These messages come to ClbWndProc because it is the parent
  973. // of the list box, but they are really intended for the parent
  974. // of the Clb.
  975. //
  976. HWND hWndParent;
  977. //
  978. // Forward the message to the Clb's parent if it has a parent.
  979. //
  980. hWndParent = GetParent( hWnd );
  981. DbgHandleAssert( hWndParent );
  982. if ( hWndParent != NULL ) {
  983. //
  984. // Replace the control id and handle with the Clb's.
  985. //
  986. *((WORD *)(&wParam)) = (WORD)GetDlgCtrlID( hWnd );
  987. DbgAssert( LOWORD( wParam ) != 0 );
  988. lParam = ( LPARAM ) hWnd;
  989. //
  990. // Forward the message...
  991. //
  992. return SendMessage(
  993. hWndParent,
  994. message,
  995. wParam,
  996. lParam
  997. );
  998. }
  999. }
  1000. }
  1001. break;
  1002. }
  1003. break;
  1004. //
  1005. // Forward to listbox.
  1006. //
  1007. case LB_GETCURSEL:
  1008. case LB_SETCURSEL:
  1009. case LB_FINDSTRING:
  1010. case LB_GETITEMDATA:
  1011. case LB_RESETCONTENT:
  1012. case WM_CHAR:
  1013. case WM_GETDLGCODE:
  1014. case WM_KILLFOCUS:
  1015. return SendMessage(
  1016. ClbInfo->hWndListBox,
  1017. message,
  1018. wParam,
  1019. lParam
  1020. );
  1021. case WM_SETFOCUS:
  1022. {
  1023. SetFocus(
  1024. ClbInfo->hWndListBox
  1025. );
  1026. return 0;
  1027. }
  1028. case WM_COMPAREITEM:
  1029. {
  1030. //
  1031. // This message comes to ClbWndProc because it is the parent
  1032. // of the list box, but is really intended for the parent
  1033. // of the Clb.
  1034. //
  1035. HWND hWndParent;
  1036. //
  1037. // Forward the message to the Clb's parent if it has a parent.
  1038. //
  1039. hWndParent = GetParent( hWnd );
  1040. DbgHandleAssert( hWndParent );
  1041. if ( hWndParent != NULL ) {
  1042. int ControlId;
  1043. LPCOMPAREITEMSTRUCT lpcis;
  1044. lpcis = ( LPCOMPAREITEMSTRUCT ) lParam;
  1045. ControlId = GetDlgCtrlID( hWnd );
  1046. DbgAssert( ControlId != 0 );
  1047. //
  1048. // Modify the COMPAREITEMSTRUCT so that it refers to the Clb.
  1049. //
  1050. lpcis->CtlID = ControlId;
  1051. lpcis->hwndItem = hWnd;
  1052. //
  1053. // Forward the message...
  1054. //
  1055. return SendMessage(
  1056. hWndParent,
  1057. message,
  1058. ( WPARAM ) ControlId,
  1059. lParam
  1060. );
  1061. }
  1062. break;
  1063. }
  1064. case WM_DELETEITEM:
  1065. {
  1066. LPDELETEITEMSTRUCT lpditms;
  1067. LPCLB_ROW ClbRow;
  1068. DWORD i;
  1069. DbgAssert( wParam == ID_LISTBOX );
  1070. //
  1071. // Retrieve the pointer to the DELETEITEMSTRUCT.
  1072. //
  1073. lpditms = ( LPDELETEITEMSTRUCT ) lParam;
  1074. DbgAssert(( lpditms->CtlType == ODT_LISTBOX )
  1075. &&( lpditms->CtlID == ID_LISTBOX ));
  1076. //
  1077. // If there is no data, just return.
  1078. //
  1079. if ( lpditms->itemData == 0 ) {
  1080. return TRUE;
  1081. }
  1082. //
  1083. // Retrieve the CLB_ROW object for this row.
  1084. //
  1085. ClbRow = ( LPCLB_ROW ) lpditms->itemData;
  1086. //
  1087. // For each column delete the string.
  1088. //
  1089. for ( i = 0; i < ClbInfo->Columns; i++ ) {
  1090. //
  1091. // Strings were copied with _tcsdup so they must be
  1092. // freed with free( ).
  1093. //
  1094. free( ClbRow->Strings[ i ].String );
  1095. }
  1096. //
  1097. // Free the CLB_STRING object.
  1098. //
  1099. Success = FreeObject( ClbRow->Strings );
  1100. DbgAssert( Success );
  1101. //
  1102. // Free the CLB_ROW object.
  1103. //
  1104. Success = FreeObject( ClbRow );
  1105. DbgAssert( Success );
  1106. return TRUE;
  1107. }
  1108. case WM_DRAWITEM:
  1109. {
  1110. LPDRAWITEMSTRUCT lpdis;
  1111. BOOL DrawFocus;
  1112. DbgAssert( wParam == ID_LISTBOX );
  1113. //
  1114. // Retrieve the pointer to the DRAWITEMSTRUCT.
  1115. //
  1116. lpdis = ( LPDRAWITEMSTRUCT ) lParam;
  1117. DbgAssert(( lpdis->CtlType == ODT_LISTBOX )
  1118. &&( lpdis->CtlID == ID_LISTBOX ));
  1119. //
  1120. // If there is no data, just return.
  1121. //
  1122. if ( lpdis->itemData == 0 ) {
  1123. return TRUE;
  1124. }
  1125. if ( lpdis->itemAction & ( ODA_DRAWENTIRE | ODA_SELECT )) {
  1126. DWORD i;
  1127. LPCLB_ROW ClbRow;
  1128. COLORREF TextColor;
  1129. COLORREF BkColor;
  1130. //
  1131. // Retrieve the CLB_ROW object for this row.
  1132. //
  1133. ClbRow = ( LPCLB_ROW ) lpdis->itemData;
  1134. //
  1135. // If the item is selected, set the selection colors.
  1136. //
  1137. if ( lpdis->itemState & ODS_SELECTED ) {
  1138. BkColor = COLOR_HIGHLIGHT;
  1139. TextColor = COLOR_HIGHLIGHTTEXT;
  1140. } else {
  1141. BkColor = COLOR_WINDOW;
  1142. TextColor = COLOR_WINDOWTEXT;
  1143. }
  1144. BkColor = GetSysColor( BkColor );
  1145. TextColor = GetSysColor( TextColor );
  1146. BkColor = SetBkColor( lpdis->hDC, BkColor );
  1147. DbgAssert( BkColor != CLR_INVALID );
  1148. TextColor = SetTextColor( lpdis->hDC, TextColor );
  1149. DbgAssert( TextColor != CLR_INVALID );
  1150. //
  1151. // For each column display the text.
  1152. //
  1153. for ( i = 0; i < ClbInfo->Columns; i++ ) {
  1154. RECT ClipOpaqueRect;
  1155. int x;
  1156. int Left;
  1157. UINT GdiErr;
  1158. //
  1159. // Depending on the format, adjust the alignment reference
  1160. // point (x) and the clipping rectangles left edge so that
  1161. // there are five pixels between each column.
  1162. //
  1163. switch ( ClbRow->Strings[ i ].Format ) {
  1164. case CLB_LEFT:
  1165. if ( i == 0 ) {
  1166. x = 2;
  1167. } else {
  1168. x = ClbInfo->Right[ i - 1 ] + 2;
  1169. }
  1170. Left = x - 2;
  1171. break;
  1172. case CLB_RIGHT:
  1173. if ( i == 0 ) {
  1174. Left = 0;
  1175. } else {
  1176. Left = ClbInfo->Right[ i - 1 ];
  1177. }
  1178. x = ClbInfo->Right[ i ] - 3;
  1179. break;
  1180. default:
  1181. DbgAssert( FALSE );
  1182. }
  1183. //
  1184. // Set the format for this column.
  1185. //
  1186. GdiErr = SetTextAlign(
  1187. lpdis->hDC,
  1188. ClbRow->Strings[ i ].Format
  1189. | TA_TOP
  1190. );
  1191. DbgAssert( GdiErr != GDI_ERROR );
  1192. //
  1193. // Clip each string to its column width less two pixels
  1194. // (for asthetics).
  1195. //
  1196. Success = SetRect(
  1197. &ClipOpaqueRect,
  1198. Left,
  1199. lpdis->rcItem.top,
  1200. ClbInfo->Right[ i ],
  1201. lpdis->rcItem.bottom
  1202. );
  1203. DbgAssert( Success );
  1204. Success = ExtTextOut(
  1205. lpdis->hDC,
  1206. x,
  1207. lpdis->rcItem.top,
  1208. ETO_CLIPPED
  1209. | ETO_OPAQUE,
  1210. &ClipOpaqueRect,
  1211. ClbRow->Strings[ i ].String,
  1212. ClbRow->Strings[ i ].Length,
  1213. NULL
  1214. );
  1215. DbgAssert( Success );
  1216. //
  1217. // If the item has the focus, draw the focus rectangle.
  1218. //
  1219. DrawFocus = lpdis->itemState & ODS_FOCUS;
  1220. }
  1221. } else {
  1222. //
  1223. // If the Clb has the focus, display a focus rectangle
  1224. // around the selected item.
  1225. //
  1226. DrawFocus = lpdis->itemAction & ODA_FOCUS;
  1227. }
  1228. //
  1229. // If needed, toggle the focus rectangle.
  1230. //
  1231. if ( DrawFocus ) {
  1232. Success = DrawFocusRect(
  1233. lpdis->hDC,
  1234. &lpdis->rcItem
  1235. );
  1236. DbgAssert( Success );
  1237. }
  1238. return TRUE;
  1239. }
  1240. case WM_NOTIFY:
  1241. {
  1242. HD_NOTIFY * lpNot;
  1243. HD_ITEM *pHDI;
  1244. lpNot = (HD_NOTIFY *)lParam;
  1245. pHDI = lpNot->pitem;
  1246. switch ( lpNot->hdr.code) {
  1247. static
  1248. DRAW_ERASE_LINE DrawEraseLine;
  1249. static
  1250. HPEN hPen;
  1251. static
  1252. HDC hDCClientListBox;
  1253. HD_ITEM hdi;
  1254. UINT iRight;
  1255. UINT i;
  1256. RECT ClientRectHeader;
  1257. case HDN_BEGINTRACK:
  1258. {
  1259. RECT ClientRectListBox;
  1260. //
  1261. // Get thd HDC for the list box.
  1262. //
  1263. hDCClientListBox = GetDC( ClbInfo->hWndListBox );
  1264. DbgHandleAssert( hDCClientListBox );
  1265. if (hDCClientListBox == NULL)
  1266. return FALSE;
  1267. //
  1268. // Create the pen used to display the drag position and
  1269. // select it into the in list box client area DC. Also set
  1270. // the ROP2 code so that drawing with the pen twice in the
  1271. // same place will erase it. This is what allows the
  1272. // line to drag.
  1273. //
  1274. hPen = CreatePen( PS_DOT, 1, RGB( 255, 255, 255 ));
  1275. DbgHandleAssert( hPen );
  1276. hPen = SelectObject( hDCClientListBox, hPen );
  1277. SetROP2( hDCClientListBox, R2_XORPEN );
  1278. //
  1279. // Set up the DRAW_ERASE_LINE structure so that the drag line is
  1280. // drawn from the top to the bottom of the list box at the
  1281. // current drag position.
  1282. //
  1283. Success = GetClientRect(
  1284. ClbInfo->hWndListBox,
  1285. &ClientRectListBox
  1286. );
  1287. DbgAssert( Success );
  1288. //
  1289. // Draw the initial drag line from the top to the bottom
  1290. // of the list box equivalent with the header edge grabbed
  1291. // by the user.
  1292. //
  1293. DrawEraseLine.Draw.Src.x = ClbInfo->Right[ pHDI->cxy ];
  1294. DrawEraseLine.Draw.Src.y = 0;
  1295. DrawEraseLine.Draw.Dst.x = ClbInfo->Right[ pHDI->cxy ];
  1296. DrawEraseLine.Draw.Dst.y = ClientRectListBox.bottom
  1297. - ClientRectListBox.top;
  1298. Success = DrawLine( hDCClientListBox, &DrawEraseLine );
  1299. DbgAssert( Success );
  1300. return 0;
  1301. }
  1302. case HDN_TRACK:
  1303. {
  1304. //DWORD Columns;
  1305. //
  1306. // Get new drag position.
  1307. //
  1308. iRight = 0;
  1309. hdi.mask = HDI_WIDTH;
  1310. for ( i = 0; i < ClbInfo->Columns - 1; i++ ) {
  1311. if (i != (UINT)lpNot->iItem) {
  1312. Header_GetItem(ClbInfo->hWndHeader, i, &hdi);
  1313. } else {
  1314. hdi.cxy = pHDI->cxy;
  1315. }
  1316. iRight += hdi.cxy;
  1317. ClbInfo->Right[i] = iRight;
  1318. }
  1319. GetClientRect( ClbInfo->hWndHeader, &ClientRectHeader );
  1320. ClbInfo->Right[i] = ClientRectHeader.right;
  1321. //
  1322. // Erase the old line and draw the new one at the new
  1323. // drag position.
  1324. //
  1325. Success = RedrawVerticalLine(
  1326. hDCClientListBox,
  1327. ClbInfo->Right[lpNot->iItem],
  1328. &DrawEraseLine
  1329. );
  1330. DbgAssert( Success );
  1331. return 0;
  1332. }
  1333. case HDN_ENDTRACK:
  1334. //
  1335. // Replace the old pen and delete the one created
  1336. // during HBN_BEGINDRAG.
  1337. //
  1338. hPen = SelectObject( hDCClientListBox, hPen );
  1339. if (hPen) {
  1340. Success = DeleteObject( hPen );
  1341. DbgAssert( Success );
  1342. }
  1343. //
  1344. // Release the DC for the list box.
  1345. //
  1346. Success = ReleaseDC( ClbInfo->hWndListBox, hDCClientListBox );
  1347. DbgAssert( Success );
  1348. Success = RedrawWindow(
  1349. hWnd,
  1350. NULL,
  1351. NULL,
  1352. RDW_ERASE
  1353. | RDW_INVALIDATE
  1354. | RDW_UPDATENOW
  1355. | RDW_ALLCHILDREN
  1356. );
  1357. DbgAssert( Success );
  1358. return 0;
  1359. }
  1360. break;
  1361. }
  1362. case WM_SETTEXT:
  1363. //
  1364. // Adjust the column number and widths based on the heading text.
  1365. //
  1366. Success = AdjustClbHeadings( hWnd, ClbInfo, ( LPCWSTR ) lParam );
  1367. DbgAssert( Success );
  1368. return Success;
  1369. case WM_SIZE:
  1370. {
  1371. HDWP hDWP;
  1372. LONG Width;
  1373. LONG Height;
  1374. LONG Style;
  1375. LONG VScrollWidth;
  1376. Width = LOWORD( lParam );
  1377. Height = HIWORD( lParam );
  1378. hDWP = BeginDeferWindowPos( 2 );
  1379. DbgHandleAssert( hDWP );
  1380. if (hDWP == NULL)
  1381. return FALSE;
  1382. //
  1383. // Retrieve the list box's styles.
  1384. //
  1385. Style = GetWindowLong(
  1386. ClbInfo->hWndListBox,
  1387. GWL_STYLE
  1388. );
  1389. //
  1390. // If the list box has a vertical scroll bar compute its
  1391. // width so that the header window's width can be adjusted
  1392. // appropriately.
  1393. //
  1394. VScrollWidth = ( Style & WS_VSCROLL )
  1395. ? GetSystemMetrics( SM_CXVSCROLL )
  1396. + ( GetSystemMetrics( SM_CXBORDER ) * 2 )
  1397. : 0;
  1398. //
  1399. // Size the header window to the width of the Clb and its
  1400. // default / original height.
  1401. //
  1402. hDWP = DeferWindowPos(
  1403. hDWP,
  1404. ClbInfo->hWndHeader,
  1405. NULL,
  1406. 0,
  1407. 0,
  1408. Width - VScrollWidth,
  1409. ClbInfo->HeaderHeight,
  1410. SWP_NOACTIVATE
  1411. | SWP_NOMOVE
  1412. | SWP_NOZORDER
  1413. );
  1414. DbgHandleAssert( hDWP );
  1415. if (hDWP == NULL)
  1416. return FALSE;
  1417. //
  1418. // If the list box has a vertical scroll bar, bump the width
  1419. // and height by two so that its border overwrites the Clb
  1420. // border. This eliminates a double border (and a gap) between
  1421. // the right and bottom edges of the scroll bar and the Clb.
  1422. //
  1423. if ( Style & WS_VSCROLL ) {
  1424. Height += 2;
  1425. Width += 2;
  1426. }
  1427. //
  1428. // Size the list box so that it is the size of the Clb less
  1429. // the height of the header window less the height of the
  1430. // border.
  1431. //
  1432. hDWP = DeferWindowPos(
  1433. hDWP,
  1434. ClbInfo->hWndListBox,
  1435. NULL,
  1436. 0,
  1437. 0,
  1438. Width,
  1439. Height
  1440. - ClbInfo->HeaderHeight
  1441. - 3,
  1442. SWP_NOACTIVATE
  1443. | SWP_NOMOVE
  1444. | SWP_NOZORDER
  1445. );
  1446. DbgHandleAssert( hDWP );
  1447. if (hDWP == NULL)
  1448. return FALSE;
  1449. Success = EndDeferWindowPos( hDWP );
  1450. DbgAssert( Success );
  1451. break;
  1452. }
  1453. }
  1454. }
  1455. return DefWindowProc( hWnd, message, wParam, lParam );
  1456. }