home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx2.zip / listmgr.c < prev    next >
C/C++ Source or Header  |  1994-04-28  |  88KB  |  2,544 lines

  1. #pragma title("List Box Replacement  --  Version 1.1 -- (ListMgr.C)")
  2. #pragma subtitle("   List Manager - Interface Definitions")
  3.  
  4. /* Program name: Listbox.Dll  Title: A List Box Replacement        */
  5. /*                                    */
  6. /* OS/2 Developer Magazine, Issue:  May '94, page 12                    */
  7. /* Author:  Mark Benge       IBM Corp.                    */
  8. /*        Matt Smith       Prominare Inc.                */
  9. /* Description:  Replacement for OS/2 List Box, first of a series.    */
  10. /*                                    */
  11. /* Program Requirements:  OS/2 2.x                    */
  12. /*              IBM C Set++                    */
  13. /*              WATCOM C 386/9.0                */
  14. /*              Borland C++ for OS/2                */
  15. /*              OS/2 Toolkit                    */
  16.  
  17. /* Copyright ╕ International Business Machines Corp. 1991-1994        */
  18. /* Copyright ╕ 1989-1994  Prominare Inc.  All Rights Reserved.        */
  19.  
  20. /************************************************************************/
  21. /************************************************************************/
  22. /*               DISCLAIMER OF WARRANTIES.            */
  23. /************************************************************************/
  24. /************************************************************************/
  25. /*     The following [enclosed] code is source code created by the    */
  26. /*     authors.  This source code is  provided to you solely        */
  27. /*     for the purpose of assisting you in the development of your    */
  28. /*     applications.  The code is provided "AS IS", without             */
  29. /*     warranty of any kind.  The authors shall not be liable        */
  30. /*     for any damages arising out of your use of the source code,    */
  31. /*     even if they have been advised of the possibility of such    */
  32. /*     damages.  It is provided purely for instructional and        */
  33. /*     illustrative purposes.                        */
  34. /************************************************************************/
  35. /************************************************************************/
  36.  
  37. #pragma info(noext)
  38. #pragma strings(readonly)
  39.  
  40. #define INCL_DOS           /* Include OS/2 DOS Kernal        */
  41. #define INCL_GPI           /* Include OS/2 PM GPI Interface    */
  42. #define INCL_WIN           /* Include OS/2 PM Windows Interface */
  43.  
  44. #include <os2.h>
  45. #include <setjmp.h>
  46. #include <string.h>
  47.  
  48. #include "listbox.h"
  49.  
  50. /* This module contains the routines that handle the list management    */
  51. /* for the list box.                            */
  52. /*                                    */
  53. /* Equivalent command line invocation of each module using the        */
  54. /* IBM C Set++ Compiler Version 2.0 is:                 */
  55. /*                                    */
  56. /*     Icc -G3e- -O+ -Rn -C -W3 -FoListMgr ListMgr.C            */
  57.  
  58. /* Filename:   ListMgr.C                        */
  59.  
  60. /*  Version:   1.1                            */
  61. /*  Created:   1993-10-14                        */
  62. /*  Revised:   1994-03-09                        */
  63.  
  64. /* Routines:   static VOID SortAscending(PLISTITEM *pli, INT sLeft,    */
  65. /*                     INT sRight);            */
  66. /*           static VOID SortDescending(PLISTITEM *pli, INT sLeft,    */
  67. /*                      INT sRight);            */
  68. /*           static INT strnicmp(const CHAR *psz1, const CHAR *psz2,    */
  69. /*                   UINT n);                */
  70. /*           static VOID RefreshList(PLISTBOXWIN plbw, LONG iItem);    */
  71. /*           INT stricmp(const CHAR *psz1, const CHAR *psz2);     */
  72. /*           LONG lSetItemText(HHEAPMEM hHeap, HWND hWnd,        */
  73. /*                 PLISTITEM pli, PSZ pszText);        */
  74. /*           VOID SaveExtendedState(PLISTBOXWIN plbw);        */
  75. /*           VOID RestoreExtendedState(PLISTBOXWIN plbw);        */
  76. /*           BOOL fSelectMultipleItem(PLISTBOXWIN plbw, LONG iCol,    */
  77. /*                    LONG iSelected, BOOL fSelect);    */
  78. /*           BOOL fSelectItem(PLISTBOXWIN plbw, LONG iCol,        */
  79. /*                LONG iSelected, BOOL fSelect);        */
  80. /*           VOID SelectExtendedItems(PLISTBOXWIN plbw, LONG iCol,    */
  81. /*                    LONG iSelected);        */
  82. /*           VOID SetControlDataList(PLISTBOXWIN plbw, ULONG cItems,    */
  83. /*                       PBYTE pb);            */
  84. /*           MRESULT EXPENTRY mrBaseListHandler(HWND hWnd, ULONG msg, */
  85. /*                          MPARAM mp1,        */
  86. /*                          MPARAM mp2);        */
  87. /*           MRESULT EXPENTRY mrExtendedListHandler(HWND hWnd,    */
  88. /*                              ULONG msg,    */
  89. /*                              MPARAM mp1,    */
  90. /*                              MPARAM mp2);    */
  91.  
  92.  
  93. /* -------------------------------------------------------------------- */
  94.  
  95. /* Standard List Box messages                        */
  96. /*                                    */
  97. /*     LM_QUERYITEMCOUNT      0x0160                */
  98. /*     LM_INSERTITEM          0x0161                */
  99. /*     LM_SETTOPINDEX          0x0162                */
  100. /*     LM_DELETEITEM          0x0163                */
  101. /*     LM_SELECTITEM          0x0164                */
  102. /*     LM_QUERYSELECTION      0x0165                */
  103. /*     LM_SETITEMTEXT          0x0166                */
  104. /*     LM_QUERYITEMTEXTLENGTH      0x0167                */
  105. /*     LM_QUERYITEMTEXT       0x0168                */
  106. /*     LM_SETITEMHANDLE       0x0169                */
  107. /*     LM_QUERYITEMHANDLE      0x016a                */
  108. /*     LM_SEARCHSTRING          0x016b                */
  109. /*     LM_SETITEMHEIGHT       0x016c                */
  110. /*     LM_QUERYTOPINDEX       0x016d                */
  111. /*     LM_DELETEALL          0x016e                */
  112.  
  113. jmp_buf jBuf;               /* Jump Buffer            */
  114.  
  115. /************************************************************************/
  116. /*                                    */
  117. /* Module Prototype Definitions                     */
  118. /*                                    */
  119. /************************************************************************/
  120.  
  121. static VOID SortAscending(PLISTITEM *pli, INT sLeft, INT sRight);
  122. static VOID SortDescending(PLISTITEM *pli, INT sLeft, INT sRight);
  123. static VOID RefreshList(PLISTBOXWIN plbw, LONG iItem);
  124. APIRET APIENTRY ListBoxExceptionHandler(PEXCEPTIONREPORTRECORD pxcptrepr,
  125.                     PEXCEPTIONREGISTRATIONRECORD pxcptregr,
  126.                     PCONTEXTRECORD pcr, PVOID sysinfo);
  127.  
  128. /************************************************************************/
  129. /************************************************************************/
  130. /*                                    */
  131. /* Module Private Functions                        */
  132. /*                                    */
  133. /************************************************************************/
  134. /************************************************************************/
  135.  
  136. #pragma subtitle("   List Manager - Ascending Sort Routine")
  137. #pragma page( )
  138.  
  139. /* --- SortAscending ---------------------------------- [ Private ] --- */
  140. /*                                    */
  141. /*     This function is used to sort the list box entries in ascending    */
  142. /*     order.  The routine implemented is the "Quick Sort" algorithm.   */
  143. /*     The function uses recursion to perform the sort.  All sorts of    */
  144. /*     of the list box are case insensitive.                */
  145. /*                                    */
  146. /*     Upon Entry:                            */
  147. /*                                    */
  148. /*     PLISTITEM pli;     = List Box Item Array Pointer            */
  149. /*     INT     sLeft;  = Low Index Value                */
  150. /*     INT     sRight; = High Index Value                */
  151. /*                                    */
  152. /*     Upon Exit:                            */
  153. /*                                    */
  154. /*     Nothing                                */
  155. /*                                    */
  156. /* -------------------------------------------------------------------- */
  157.  
  158. static VOID SortAscending(PLISTITEM *pli, INT sLeft, INT sRight)
  159.  
  160. {
  161. PSZ      pszText;           /* String Pointer            */
  162. PLISTITEM pliSwap;           /* List Item Holder            */
  163. register INT i;            /* Low Index Counter         */
  164. register INT n;            /* High Index Counter        */
  165.  
  166.                /* Determine target pointer and retrieve string    */
  167.                /* address                    */
  168.  
  169. pszText = pli[((i = sLeft) + (n = sRight)) / 2]->pszText;
  170.  
  171. do
  172.    {
  173.    while ( (stricmp(pli[i]->pszText, pszText) < 0) && (i < sRight) )
  174.        ++i;
  175.    while ( (stricmp(pli[n]->pszText, pszText) > 0) && (n > sLeft) )
  176.        --n;
  177.  
  178.    if ( i <= n )
  179.        {
  180.        pliSwap = pli[i];
  181.        pli[i++] = pli[n];
  182.        pli[n--] = pliSwap;
  183.        }
  184.    } while ( i <= n );
  185.  
  186. if ( sLeft < n )
  187.    SortAscending(pli, sLeft, n);
  188.  
  189. if ( i < sRight )
  190.    SortAscending(pli, i, sRight);
  191. }
  192. #pragma subtitle("   List Manager - Descending Sort Routine")
  193. #pragma page( )
  194.  
  195. /* --- SortDescending --------------------------------- [ Private ] --- */
  196. /*                                    */
  197. /*     This function is used to sort the list box entries in descending */
  198. /*     order.  The routine implemented is the "Quick Sort" algorithm.   */
  199. /*     The function uses recursion to perform the sort.  All sorts of    */
  200. /*     of the list box are case insensitive.                */
  201. /*                                    */
  202. /*     Upon Entry:                            */
  203. /*                                    */
  204. /*     PLISTITEM pli;     = List Box Item Array Pointer            */
  205. /*     INT     sLeft;  = Low Index Value                */
  206. /*     INT     sRight; = High Index Value                */
  207. /*                                    */
  208. /*     Upon Exit:                            */
  209. /*                                    */
  210. /*     Nothing                                */
  211. /*                                    */
  212. /* -------------------------------------------------------------------- */
  213.  
  214. static VOID SortDescending(PLISTITEM *pli, INT sLeft, INT sRight)
  215.  
  216. {
  217. PLISTITEM pliSwap;           /* List Item Holder            */
  218. PSZ      pszText;           /* String Pointer            */
  219. register INT i;            /* Low Index Counter         */
  220. register INT n;            /* High Index Counter        */
  221.  
  222.                /* Determine target pointer and retrieve string    */
  223.                /* address                    */
  224.  
  225. pszText = pli[((i = sLeft) + (n = sRight)) / 2]->pszText;
  226.  
  227. do
  228.    {
  229.    while ( (stricmp(pli[i]->pszText, pszText) > 0) && (i < sRight) )
  230.        ++i;
  231.    while ( (stricmp(pli[n]->pszText, pszText) < 0) && (n > sLeft) )
  232.        --n;
  233.  
  234.    if ( i <= n )
  235.        {
  236.        pliSwap = pli[i];
  237.        pli[i++] = pli[n];
  238.        pli[n--] = pliSwap;
  239.        }
  240.    } while ( i <= n );
  241.  
  242. if ( sLeft < n )
  243.    SortDescending(pli, sLeft, n);
  244.  
  245. if ( i < sRight )
  246.    SortDescending(pli, i, sRight);
  247. }
  248.  
  249. #if defined(__IBMC__) || defined(__IBMCPP__)
  250.  
  251. #pragma subtitle("   List Manager - String Case Insensitive Compare Function")
  252. #pragma page( )
  253.  
  254. /* --- stricmp ---------------------------------------- [ Private ] --- */
  255. /*                                    */
  256. /*     This function is used to compare two strings for equality being    */
  257. /*     insensitive to case.  This function is defined here since the    */
  258. /*     IBM C Set/2 and C Set++ compilers have decided in their        */
  259. /*     collective wisdom to not supply this function within the     */
  260. /*     subsystem support libraries!!!                    */
  261. /*                                    */
  262. /*     Upon Entry:                            */
  263. /*                                    */
  264. /*     PSZ psz1; = String 1                        */
  265. /*     PSZ psz2; = String 2                        */
  266. /*                                    */
  267. /*     Upon Exit:                            */
  268. /*                                    */
  269. /*     stricmp = -1 : String 1    < String 2                */
  270. /*           =  0 : String 1 == String 2                */
  271. /*           =  1 : String 1    > String 2                */
  272. /*                                    */
  273. /* -------------------------------------------------------------------- */
  274.  
  275. INT stricmp(const CHAR *psz1, const CHAR *psz2)
  276.  
  277. {
  278. while ( *psz1 && *psz2 && (*psz1 & 223) == (*psz2 & 223) )
  279.    {
  280.    ++psz1;
  281.    ++psz2;
  282.    }
  283.  
  284. return((*psz1 & 223) - (*psz2 & 223));
  285. }
  286. #pragma subtitle("   List Manager - String Case Insensitive Compare Function")
  287. #pragma page( )
  288.  
  289. /* --- strnicmp --------------------------------------- [ Private ] --- */
  290. /*                                    */
  291. /*     This function is used to compare two strings for equality being    */
  292. /*     insensitive to case.  This function is defined here since the    */
  293. /*     IBM C Set/2 and C Set++ compilers have decided in their        */
  294. /*     collective wisdom to not supply this function within the     */
  295. /*     subsystem support libraries!!!                    */
  296. /*                                    */
  297. /*     Upon Entry:                            */
  298. /*                                    */
  299. /*     PSZ  psz1; = String 1                        */
  300. /*     PSZ  psz2; = String 2                        */
  301. /*     UINT n;      = Number of Characters to Compare            */
  302. /*                                    */
  303. /*     Upon Exit:                            */
  304. /*                                    */
  305. /*     strnicmp = -1 : String 1  < String 2                */
  306. /*        =  0 : String 1 == String 2                */
  307. /*        =  1 : String 1  > String 2                */
  308. /*                                    */
  309. /* -------------------------------------------------------------------- */
  310.  
  311. static INT strnicmp(const CHAR *psz1, const CHAR *psz2, UINT n)
  312.  
  313. {
  314. while ( n-- && *psz1 && *psz2 && (*psz1 & 223) == (*psz2 & 223) )
  315.    {
  316.    ++psz1;
  317.    ++psz2;
  318.    }
  319.  
  320. return((*psz1 & 223) - (*psz2 & 223));
  321. }
  322.  
  323. #endif
  324.  
  325. #pragma subtitle("   List Manager - Refresh List Determination Function")
  326. #pragma page( )
  327.  
  328. /* --- fRefreshList ----------------------------------- [ Private ] --- */
  329. /*                                    */
  330. /*     This function is used to determine if the list box needs to be    */
  331. /*     refreshed after an item has been inserted in it.         */
  332. /*                                    */
  333. /*     Upon Entry:                            */
  334. /*                                    */
  335. /*     PLISTBOXWIN plbw; = List Box Internal Data Pointer        */
  336. /*     LONG      iItem; = Inserted Item Index                */
  337. /*                                    */
  338. /*     Upon Exit:                            */
  339. /*                                    */
  340. /*     Nothing                                */
  341. /*                                    */
  342. /* -------------------------------------------------------------------- */
  343.  
  344. static VOID RefreshList(PLISTBOXWIN plbw, LONG iItem)
  345.  
  346. {
  347. RECTL rcl;               /* Display Rectangle         */
  348.  
  349. if ( WinIsWindowShowing(plbw->hWnd) )
  350.    {
  351.    if ( iItem < (plbw->iVertScroll + plbw->cLinesPage) )
  352.        if ( iItem < plbw->iVertScroll )
  353.        WinInvalidateRect(plbw->hWnd, &plbw->rcl, FALSE);
  354.        else
  355.        {
  356.        rcl = plbw->rcl;
  357.        rcl.yTop = plbw->rcl.yTop - (iItem - plbw->iVertScroll) * plbw->cyItem;
  358.        if ( plbw->cItems < plbw->cLinesPage )
  359.            rcl.yBottom = plbw->rcl.yTop - plbw->cItems * plbw->cyItem;
  360.        WinInvalidateRect(plbw->hWnd, &rcl, FALSE);
  361.        }
  362.    UpdateScrollBars(plbw);
  363.    }
  364. else
  365.    plbw->fDirty = TRUE;
  366. }
  367.  
  368. /************************************************************************/
  369. /************************************************************************/
  370. /*                                    */
  371. /* Module Public Functions                        */
  372. /*                                    */
  373. /************************************************************************/
  374. /************************************************************************/
  375.  
  376. #pragma subtitle("   List Manager - Descending Insert Item Locate Routine")
  377. #pragma page( )
  378.  
  379. /* --- lSetItemText ----------------------------------- [ Private ] --- */
  380. /*                                    */
  381. /*     This function is used to allocate the memory for the text of    */
  382. /*     the item being added or replaced.  The routine also calculates    */
  383. /*     the width of the text to allow the proper updating of the    */
  384. /*     horizontal scroll bar.                        */
  385. /*                                    */
  386. /*     Upon Entry:                            */
  387. /*                                    */
  388. /*     HHEAPMEM  hHeap;      = Heap Handle                */
  389. /*     HWND     hWnd;         = List Box Window Handle            */
  390. /*     PLISTITEM pli;         = List Box Item Array Pointer        */
  391. /*     PSZ     pszText;    = Inserted Item Text            */
  392. /*                                    */
  393. /*     Upon Exit:                            */
  394. /*                                    */
  395. /*     lSetItemText = Item Width in Pixels                */
  396. /*                                    */
  397. /* -------------------------------------------------------------------- */
  398.  
  399. LONG lSetItemText(HHEAPMEM hHeap, HWND hWnd, PLISTITEM pli, PSZ pszText)
  400.  
  401. {
  402. HPS    hPS;               /* Presentation Space Handle     */
  403. POINTL rgptl[TXTBOX_COUNT];       /* Text Box Point Array        */
  404.  
  405.                /* Check to see that the text for the item is    */
  406.                /* not a NULL pointer                */
  407. if ( pszText )
  408.     {
  409.                /* Allocate space for the text of the item and    */
  410.                /* copy the text to the holder            */
  411.     pli->cText = strlen(pszText);
  412.     memcpy(pli->pszText = (PSZ)HeapMalloc(hHeap, pli->cText + 1),
  413.        pszText, pli->cText);
  414.  
  415.                /* Get the presentation space for the list box    */
  416.  
  417.    if ( (hPS = WinGetPS(hWnd)) != (HPS)NULL )
  418.        {
  419.                /* Get the display rectangle for the text    */
  420.  
  421.        GpiQueryTextBox(hPS, (LONG)pli->cText, pszText, 5L, rgptl);
  422.  
  423.                /* Release the presentation space        */
  424.        WinReleasePS(hPS);
  425.  
  426.                /* Calculate the width of the text        */
  427.  
  428.        pli->cxItem = rgptl[TXTBOX_CONCAT].x - rgptl[TXTBOX_BOTTOMLEFT].x + 2L;
  429.        }
  430.    else
  431.        pli->cxItem = 0L;
  432.     }
  433. else
  434.    {
  435.                /* Empty item being inserted create an empty    */
  436.                /* entry                     */
  437.  
  438.     pli->pszText = (PSZ)HeapMalloc(hHeap, 1UL);
  439.     pli->cxItem = 0L;
  440.     }
  441.  
  442. return(pli->cxItem);
  443. }
  444. #pragma subtitle("   List Manager - Extended State Save Routine")
  445. #pragma page( )
  446.  
  447. /* --- SaveExtendedState ------------------------------- [ Public ] --- */
  448. /*                                    */
  449. /*     This function is used to save the current extended selection    */
  450. /*     state so as to allow for it to be restored upon an undo        */
  451. /*     request.                             */
  452. /*                                    */
  453. /*     Upon Entry:                            */
  454. /*                                    */
  455. /*     PLISTBOXWIN plbw; = List Box Internal Data Pointer        */
  456. /*                                    */
  457. /*     Upon Exit:                            */
  458. /*                                    */
  459. /*     Nothing                                */
  460. /*                                    */
  461. /* -------------------------------------------------------------------- */
  462.  
  463. VOID SaveExtendedState(PLISTBOXWIN plbw)
  464.  
  465. {
  466. register INT i;            /* Loop Counter            */
  467.  
  468.                /* Loop through the items within the list and    */
  469.                /* save the current flags within the list    */
  470.  
  471. for ( i = 0; i < plbw->cItems; i++ )
  472.    plbw->plc[0].apli[i]->fl = (plbw->plc[0].apli[i]->fl & 0x0000ffffUL) << 16UL |
  473.                  (plbw->plc[0].apli[i]->fl & 0x0000ffffUL);
  474.  
  475.                /* Save the selection, focus and anchor indices    */
  476.  
  477. plbw->iSelectedLast = plbw->iSelected;
  478. plbw->iFocusLast    = plbw->iFocus;
  479. plbw->iAnchorLast   = plbw->iAnchor;
  480. }
  481. #pragma subtitle("   List Manager - Extended State Restore Routine")
  482. #pragma page( )
  483.  
  484. /* --- RestoreExtendedState ---------------------------- [ Public ] --- */
  485. /*                                    */
  486. /*     This function is used to restore the previous extended state    */
  487. /*     when the undo request is received.  The old state is exchanged    */
  488. /*     with the current state to allow an undo of the undo.        */
  489. /*                                    */
  490. /*     Upon Entry:                            */
  491. /*                                    */
  492. /*     PLISTBOXWIN plbw; = List Box Internal Data Pointer        */
  493. /*                                    */
  494. /*     Upon Exit:                            */
  495. /*                                    */
  496. /*     Nothing                                */
  497. /*                                    */
  498. /* -------------------------------------------------------------------- */
  499.  
  500. VOID RestoreExtendedState(PLISTBOXWIN plbw)
  501.  
  502. {
  503. LONG  iSelected;           /* Selected Item Index        */
  504. LONG  iFocus;               /* Focus Item Index            */
  505. LONG  iAnchor;               /* Anchor Item Index         */
  506. register INT i;            /* Loop Counter            */
  507.  
  508.                /* Loop through the items within the list and    */
  509.                /* exchange the current flags within the list    */
  510.  
  511. for ( i = 0; i < plbw->cItems; i++ )
  512.    plbw->plc[0].apli[i]->fl = plbw->plc[0].apli[i]->fl >> 16UL |
  513.                 (plbw->plc[0].apli[i]->fl & 0x0000ffffUL) << 16UL;
  514.  
  515.                /* Exchange the selection, focus and anchor    */
  516.                /* indices                    */
  517.  
  518. iSelected        = plbw->iSelected;
  519. iFocus            = plbw->iFocus;
  520. iAnchor         = plbw->iAnchor;
  521. plbw->iSelected     = plbw->iSelectedLast;
  522. plbw->iFocus        = plbw->iFocusLast;
  523. plbw->iAnchor        = plbw->iAnchorLast;
  524. plbw->iSelectedLast = iSelected;
  525. plbw->iFocusLast    = iFocus;
  526. plbw->iAnchorLast   = iAnchor;
  527. }
  528. #pragma subtitle("   List Manager - Item Selection Routine")
  529. #pragma page( )
  530.  
  531. /* --- fSelectMultipleItem ----------------------------- [ Public ] --- */
  532. /*                                    */
  533. /*     This function is used to select an item within the list using    */
  534. /*     the selection criteria given.  The routine is used within    */
  535. /*     multiple selection list where the selection of an item does    */
  536. /*     not change the state of the other items.             */
  537. /*                                    */
  538. /*     Upon Entry:                            */
  539. /*                                    */
  540. /*     PLISTBOXWIN plbw;      = List Box Internal Data Pointer        */
  541. /*     LONG       iCol;      = Column                    */
  542. /*     LONG       iSelected; = Selected Item                */
  543. /*     BOOL       fSelect;   = Selection Flag                */
  544. /*                                    */
  545. /*     Upon Exit:                            */
  546. /*                                    */
  547. /*     fSelectMultipleItem =  TRUE : Item Selected            */
  548. /*               = FALSE : Item Not Selected            */
  549. /*                                    */
  550. /* -------------------------------------------------------------------- */
  551.  
  552. BOOL fSelectMultipleItem(PLISTBOXWIN plbw, LONG iCol, LONG iSelected, BOOL fSelect)
  553.  
  554. {
  555.                /* Check to see that items within the list box    */
  556.                /* and that the item requested is within the    */
  557.                /* range of items                */
  558.  
  559. if ( iSelected < plbw->cItems )
  560.    {
  561.                /* Multiple selections allowed, select or    */
  562.                /* deselected the requested item         */
  563.  
  564.    SaveSelectState(0L, iSelected);
  565.    if ( fSelect )
  566.        plbw->plc[iCol].apli[iSelected]->fl |= LI_SELECTED;
  567.    else
  568.        plbw->plc[iCol].apli[iSelected]->fl &= ~LI_SELECTED;
  569.  
  570.                /* Invert the rectangle of the entry to return    */
  571.                /* it back to its normal display colour        */
  572.  
  573.    DrawSelection(plbw, iSelected);
  574.    return(TRUE);
  575.    }
  576. return(FALSE);
  577. }
  578. #pragma subtitle("   List Manager - Item Selection Routine")
  579. #pragma page( )
  580.  
  581. /* --- fSelectItem ------------------------------------- [ Public ] --- */
  582. /*                                    */
  583. /*     This function is used to select an item within the list using    */
  584. /*     the selection criteria given.                    */
  585. /*                                    */
  586. /*     Upon Entry:                            */
  587. /*                                    */
  588. /*     PLISTBOXWIN plbw;      = List Box Internal Data Pointer        */
  589. /*     LONG       iCol;      = Column                    */
  590. /*     LONG       iSelected; = Selected Item                */
  591. /*     BOOL       fSelect;   = Selection Flag                */
  592. /*                                    */
  593. /*     Upon Exit:                            */
  594. /*                                    */
  595. /*     fSelectItem =  TRUE : Item Selected                */
  596. /*           = FALSE : Item Not Selected                */
  597. /*                                    */
  598. /* -------------------------------------------------------------------- */
  599.  
  600. BOOL fSelectItem(PLISTBOXWIN plbw, LONG iCol, LONG iSelected, BOOL fSelect)
  601.  
  602. {
  603. register INT i;            /* Loop Index            */
  604.  
  605.                /* Check to see that items within the list box    */
  606.                /* and that the item requested is within the    */
  607.                /* range of items                */
  608.  
  609. if ( iSelected < plbw->cItems )
  610.    {
  611.                /* Check to see if the list box allows for    */
  612.                /* multiple selections                */
  613.  
  614.    if ( plbw->flStyle & LS_MULTIPLESEL )
  615.        {
  616.                /* Multiple selections allowed, select or    */
  617.                /* deselected the requested item         */
  618.  
  619.        SaveSelectState(0L, iSelected);
  620.        if ( fSelect )
  621.        plbw->plc[iCol].apli[iSelected]->fl |= LI_SELECTED;
  622.        else
  623.        plbw->plc[iCol].apli[iSelected]->fl &= ~LI_SELECTED;
  624.  
  625.                /* Invert the rectangle of the entry to return    */
  626.                /* it back to its normal display colour        */
  627.  
  628.        DrawSelection(plbw, iSelected);
  629.        }
  630.    else
  631.        {
  632.        if ( plbw->flStyle & LS_EXTENDEDSEL )
  633.        for ( i = 0; i < plbw->cItems; i++ )
  634.            if ( (plbw->plc[iCol].apli[i]->fl & LI_SELECTED) &&
  635.             (i != iSelected) &&
  636.             (i != plbw->iSelected) )
  637.            {
  638.            SaveSelectState(0L, i);
  639.            plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  640.  
  641.                /* Invert the rectangle of the entry to return    */
  642.                /* it back to its normal display colour        */
  643.  
  644.            DrawSelection(plbw, i);
  645.            }
  646.                /* Single selection only allowed for the list    */
  647.                /* box, deselect the previous item and then    */
  648.                /* select the desired one            */
  649.  
  650.        SaveSelectState(0L, iSelected);
  651.        if ( fSelect )
  652.        {
  653.        if ( plbw->iSelected != LIT_NONE )
  654.            {
  655.            SaveSelectState(0L, plbw->iSelected);
  656.            plbw->plc[iCol].apli[plbw->iSelected]->fl &= ~(LI_SELECTED | LI_FOCUS);
  657.  
  658.                /* Invert the rectangle of the entry to return    */
  659.                /* it back to its normal display colour        */
  660.  
  661.            DrawSelection(plbw, plbw->iSelected);
  662.            }
  663.        plbw->plc[iCol].apli[plbw->iSelected = iSelected]->fl |= LI_SELECTED;
  664.        }
  665.        else
  666.        {
  667.        plbw->plc[iCol].apli[iSelected]->fl &= ~(LI_SELECTED | LI_FOCUS);
  668.        plbw->iSelected = LIT_NONE;
  669.        }
  670.                /* Invert the rectangle of the entry to return    */
  671.                /* it back to its normal display colour        */
  672.  
  673.        DrawSelection(plbw, iSelected);
  674.        }
  675.    return(TRUE);
  676.    }
  677. return(FALSE);
  678. }
  679. #pragma subtitle("   List Manager - Extended Selection Routine")
  680. #pragma page( )
  681.  
  682. /* --- SelectExtendedItems ----------------------------- [ Public ] --- */
  683. /*                                    */
  684. /*     This function is used to perform the extended selection using    */
  685. /*     the defined anchor point and the current item as the bounds.    */
  686. /*                                    */
  687. /*     Upon Entry:                            */
  688. /*                                    */
  689. /*     PLISTBOXWIN plbw;      = List Box Internal Data Pointer        */
  690. /*     LONG       iCol;      = Column                    */
  691. /*     LONG       iSelected; = Selected Item                */
  692. /*                                    */
  693. /*     Upon Exit:                            */
  694. /*                                    */
  695. /*     Nothing                                */
  696. /*                                    */
  697. /* -------------------------------------------------------------------- */
  698.  
  699. VOID SelectExtendedItems(PLISTBOXWIN plbw, LONG iCol, LONG iSelected)
  700.  
  701. {
  702. register INT i, n;           /* Index                */
  703.  
  704.                /* Check to see that items within the list box    */
  705.                /* and that the item requested is within the    */
  706.                /* range of items                */
  707.  
  708. if ( iSelected < plbw->cItems )
  709.    {
  710.                /* Check for the case where a selection has been */
  711.                /* made on the check box area in which case no    */
  712.                /* starting selections have been made yet    */
  713.  
  714.    if ( plbw->iSelected == -1L )
  715.        return;
  716.                /* Check to see if the selection is on the    */
  717.                /* anchor point                    */
  718.  
  719.    if ( iSelected == plbw->iAnchor )
  720.        {
  721.                /* Anchor point selected, need to deselect the    */
  722.                /* other items                    */
  723.  
  724.        if ( plbw->iSelected < plbw->iAnchor )
  725.        {
  726.        i = plbw->iSelected;
  727.        n = plbw->iAnchor;
  728.        }
  729.        else
  730.        {
  731.        n = plbw->iSelected + 1L;
  732.        i = plbw->iAnchor + 1L;
  733.        }
  734.  
  735.        for ( ; i < n; i++ )
  736.        if ( plbw->plc[iCol].apli[i]->fl & LI_SELECTED )
  737.            {
  738.            SaveSelectState(0L, i);
  739.            plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  740.  
  741.                /* Invert the rectangle of the entry to return    */
  742.                /* it back to its normal display colour        */
  743.  
  744.            DrawSelection(plbw, i);
  745.            }
  746.        }
  747.    else
  748.        {
  749.                /* Check for the case where a selection has been */
  750.                /* made on the check box area in which case no    */
  751.                /* starting selections have been made yet    */
  752.  
  753.        if ( plbw->iSelected == -1L )
  754.        return;
  755.                /* Check to see if the selection point is in    */
  756.                /* front of the anchor                */
  757.  
  758.        if ( iSelected < plbw->iAnchor )
  759.        {
  760.                /* Check to see if the selected item is in    */
  761.                /* front of the anchor in which case need to    */
  762.                /* check to see if the block selection is    */
  763.                /* changing direction in which case the items on */
  764.                /* the other side of the anchor need to be    */
  765.                /* deselected                    */
  766.  
  767.        if ( plbw->iSelected < plbw->iAnchor )
  768.            {
  769.            for ( i = plbw->iSelected; i < iSelected; i++ )
  770.            if ( plbw->plc[iCol].apli[i]->fl & LI_SELECTED )
  771.                {
  772.                SaveSelectState(0L, i);
  773.                plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  774.  
  775.                /* Invert the rectangle of the entry to return    */
  776.                /* it back to its normal display colour        */
  777.  
  778.                DrawSelection(plbw, i);
  779.                }
  780.            }
  781.        else
  782.            for ( i = plbw->iSelected; i > plbw->iAnchor; i-- )
  783.            if ( plbw->plc[iCol].apli[i]->fl & LI_SELECTED )
  784.                {
  785.                SaveSelectState(0L, i);
  786.                plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  787.  
  788.                /* Invert the rectangle of the entry to return    */
  789.                /* it back to its normal display colour        */
  790.  
  791.                DrawSelection(plbw, i);
  792.                }
  793.        i = iSelected;
  794.        n = plbw->iAnchor + 1L;
  795.        }
  796.        else
  797.                /* Item selected after the anchor point, check    */
  798.                /* to see if the previous selected item was    */
  799.                /* before the anchor, in which case need to    */
  800.                /* check to see if the block selection is    */
  801.                /* changing direction in which case the items on */
  802.                /* the other side of the anchor need to be    */
  803.                /* deselected                    */
  804.        {
  805.        if ( plbw->iSelected < plbw->iAnchor )
  806.            for ( i = plbw->iSelected; i < plbw->iAnchor; i++ )
  807.            if ( plbw->plc[iCol].apli[i]->fl & LI_SELECTED )
  808.                {
  809.                SaveSelectState(0L, i);
  810.                plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  811.  
  812.                /* Invert the rectangle of the entry to return    */
  813.                /* it back to its normal display colour        */
  814.  
  815.                DrawSelection(plbw, i);
  816.                }
  817.        n = iSelected + 1L;
  818.        i = plbw->iAnchor;
  819.        }
  820.  
  821.        for ( ; i < n; i++ )
  822.        if ( !(plbw->plc[iCol].apli[i]->fl & LI_SELECTED) )
  823.            {
  824.            SaveSelectState(0L, i);
  825.            plbw->plc[iCol].apli[i]->fl |= LI_SELECTED;
  826.  
  827.            /* Invert the rectangle of the entry to return    */
  828.            /* it back to its normal display colour        */
  829.  
  830.            DrawSelection(plbw, i);
  831.            }
  832.  
  833.        if ( iSelected > plbw->iAnchor )
  834.        for ( i = n; i <= plbw->iSelected; i++ )
  835.            if ( plbw->plc[iCol].apli[i]->fl & LI_SELECTED )
  836.            {
  837.            SaveSelectState(0L, i);
  838.            plbw->plc[iCol].apli[i]->fl &= ~LI_SELECTED;
  839.  
  840.            /* Invert the rectangle of the entry to return    */
  841.            /* it back to its normal display colour        */
  842.  
  843.            DrawSelection(plbw, i);
  844.            }
  845.        }
  846.    plbw->iSelected = iSelected;
  847.    }
  848. }
  849. #pragma subtitle("   List Manager - List Box Control Data Procedure")
  850. #pragma page( )
  851.  
  852. /* --- SetControlDataList ------------------------------ [ Public ] --- */
  853. /*                                    */
  854. /*     This function is used to decode the control data that may form    */
  855. /*     part the of the WM_CREATE message.  The control data is        */
  856. /*     designed to allow the user to specify a simple list of items    */
  857. /*     that are to be placed within the list box.            */
  858. /*                                    */
  859. /*     Upon Entry:                            */
  860. /*                                    */
  861. /*     PLISTBOXWIN plbw;   = List Box Internal Data Pointer        */
  862. /*     ULONG       cItems; = Items in Control Data List         */
  863. /*     PBYTE       pb;       = Control Data List Pointer            */
  864. /*                                    */
  865. /*     Upon Exit:                            */
  866. /*                                    */
  867. /*     Nothing                                */
  868. /*                                    */
  869. /* -------------------------------------------------------------------- */
  870.  
  871. VOID SetControlDataList(PLISTBOXWIN plbw, ULONG cItems, PBYTE pb)
  872.  
  873. {
  874. HHEAPMEM hHeap;            /* Heap Handle            */
  875. register INT i;            /* Loop Counter            */
  876. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception Record        */
  877.  
  878. if ( !cItems )
  879.    return;
  880.                /* Register exception handler that is used for    */
  881.                /* the lazy pointer validation tests        */
  882.  
  883. xcptregr.prev_structure   = NULL;
  884. xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  885.  
  886. DosSetExceptionHandler(&xcptregr);
  887.  
  888.                /* Set the jump buffer and check to see if an    */
  889.                /* exception has occurred in which case ignore    */
  890.                /* the decoding of the control data and return    */
  891. if ( setjmp(jBuf) )
  892.    {
  893.                /* Remove the exception handle since the lazy    */
  894.                /* pointer evaluation is done            */
  895.  
  896.    DosUnsetExceptionHandler(&xcptregr);
  897.    return;
  898.    }
  899.                /* Starting off the list box from scratch,    */
  900.                /* create the new heap that is to be used for    */
  901.                /* list box.  Allocate the memory needed for the */
  902.                /* control information and save the heap handle    */
  903.                /* within it.                    */
  904.  
  905. plbw->plc = (PLISTCOL)HeapMalloc(hHeap = HeapAlloc(8192UL, 4096UL), sizeof(LISTCOL));
  906.  
  907.                /* Allocate memory for the initial start of the    */
  908.                /* list.  The list is allocated in groups of 8,    */
  909.                /* hence whenever the list total is a multiple    */
  910.                /* of 8, the current list is full and needs to    */
  911.                /* be expanded.                    */
  912.  
  913. plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  914.                         ((cItems / CBLK_LIST) + 1UL) * CBLK_LIST * sizeof(PLISTITEM));
  915.  
  916.                /* Set the text of the item being inserted at    */
  917.                /* the end of the list box list and check to see */
  918.                /* if the item is wider than the rest in which    */
  919.                /* case the maximum item width should be updated */
  920.  
  921. for ( i = 0; i < cItems; i++ )
  922.    {
  923.    if ( (lSetItemText(plbw->plc[0].hHeap, plbw->hWnd, plbw->plc[0].apli[i],
  924.               pb) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  925.        plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  926.    pb += strlen(pb) + 1;
  927.    }
  928.                /* Remove the exception handle since the lazy    */
  929.                /* pointer evaluation is done            */
  930.  
  931. DosUnsetExceptionHandler(&xcptregr);
  932. }
  933. #pragma subtitle("   List Manager - List Box Window Procedure")
  934. #pragma page( )
  935.  
  936. /* --- mrBaseListHandler ------------------------------- [ Public ] --- */
  937. /*                                    */
  938. /*     This function is used to process the messages for the Colour    */
  939. /*     Wheel control window.  It should be noted that all angles    */
  940. /*     when used with sin and cosine functions are in radians.        */
  941. /*                                    */
  942. /*     Upon Entry:                            */
  943. /*                                    */
  944. /*     HWND   hWnd; = Window Handle                    */
  945. /*     ULONG  msg;  = PM Message                    */
  946. /*     MPARAM mp1;  = Message Parameter 1                */
  947. /*     MPARAM mp2;  = Message Parameter 2                */
  948. /*                                    */
  949. /*     Upon Exit:                            */
  950. /*                                    */
  951. /*     mrBaseListHandler = Message Handling Result            */
  952. /*                                    */
  953. /* -------------------------------------------------------------------- */
  954.  
  955. MRESULT EXPENTRY mrBaseListHandler(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  956.  
  957. {
  958. HHEAPMEM    hHeap;           /* Heap Handle            */
  959. LONG        iVertScroll;       /* Vertical Scroll Position        */
  960. PLISTBOXWIN plbw;           /* List Box Internal Data Pointer    */
  961. PLISTITEM   pli;           /* List Item Pointer         */
  962. RECTL        rcl;           /* Display Rectangle         */
  963. UINT        usLen;           /* Length Holder            */
  964. register INT i, n;           /* Loop Counter            */
  965. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception Record        */
  966.  
  967. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  968.  
  969. switch ( msg )
  970.    {
  971.    /*********************************************************************/
  972.    /*  Standard message:   LM_DELETEALL                 */
  973.    /*               mp1 = 0L;                    */
  974.    /*               mp2 = 0L;                    */
  975.    /*********************************************************************/
  976.  
  977.    case LM_DELETEALL :
  978.                /* Check to see if any items within the list box */
  979.                /* which if there are none, there is nothing to    */
  980.                /* delete and there is no memory to release    */
  981.  
  982.        if ( plbw->cItems )
  983.        {
  984.                /* Release the heap associated with the list box */
  985.                /* items and set the item count to zero        */
  986.  
  987.        HeapRelease(plbw->plc[0].hHeap);
  988.  
  989.        FocusChange(plbw, plbw->iFocus, FALSE);
  990.        plbw->iFocus = plbw->iSelected = LIT_NONE;
  991.        plbw->cHorzScroll =
  992.        plbw->cVertScroll =
  993.        plbw->iHorzScroll =
  994.        plbw->iVertScroll = 0L;
  995.        plbw->cItems = 0UL;
  996.  
  997.                /* Check to see if the list box is showing and    */
  998.                /* if the case clear the list area and update    */
  999.                /* the scroll bars otherwise set dirty flag to    */
  1000.                /* delay the scroll bar updating until it is    */
  1001.                /* visible                    */
  1002.  
  1003.        if ( WinIsWindowShowing(hWnd) )
  1004.            {
  1005.            WinInvalidateRect(hWnd, &plbw->rcl, FALSE);
  1006.            UpdateScrollBars(plbw);
  1007.            }
  1008.        else
  1009.            plbw->fDirty = TRUE;
  1010.        return(MRFROMLONG(TRUE));
  1011.        }
  1012.        break;
  1013.  
  1014.    /*********************************************************************/
  1015.    /*  Standard message:   LM_DELETEITEM                */
  1016.    /*               mp1 = MPFROMLONG(iItem);            */
  1017.    /*               mp2 = 0L;                    */
  1018.    /*********************************************************************/
  1019.  
  1020.    case LM_DELETEITEM :
  1021.                /* Check to see that items within the list box    */
  1022.                /* and that the item requested is within the    */
  1023.                /* range of items                */
  1024.  
  1025.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1026.        {
  1027.                /* Reduce the list box item count and check to    */
  1028.                /* see if the last item is being deleted in    */
  1029.                /* which case release the heap for the list box    */
  1030.                /* items                     */
  1031.  
  1032.        if ( --plbw->cItems == 0UL )
  1033.            {
  1034.            HeapRelease(plbw->plc[0].hHeap);
  1035.  
  1036.            FocusChange(plbw, plbw->iFocus, FALSE);
  1037.            plbw->iFocus = plbw->iSelected = LIT_NONE;
  1038.            plbw->cHorzScroll =
  1039.            plbw->cVertScroll =
  1040.            plbw->iHorzScroll =
  1041.            plbw->iVertScroll = 0L;
  1042.            }
  1043.        else
  1044.            {
  1045.                /* Release the memory allocated for the text of    */
  1046.                /* the item and shift the entires up one     */
  1047.                /* position in place of the entry being        */
  1048.                /* deleted                    */
  1049.  
  1050.            HeapFree(plbw->plc[0].hHeap, plbw->plc[0].apli[LONGFROMMP(mp1)]->pszText);
  1051.            HeapFree(plbw->plc[0].hHeap, plbw->plc[0].apli[LONGFROMMP(mp1)]);
  1052.            if ( LONGFROMMP(mp1) != plbw->cItems )
  1053.            memmove(&plbw->plc[0].apli[LONGFROMMP(mp1)], &plbw->plc[0].apli[LONGFROMMP(mp1) + 1],
  1054.                (UINT)((plbw->cItems - LONGFROMMP(mp1)) * sizeof(PLISTITEM)));
  1055.            }
  1056.        if ( (plbw->iVertScroll + plbw->cLinesPage) >= plbw->cItems )
  1057.            {
  1058.            if ( (plbw->iVertScroll = plbw->cItems - plbw->cLinesPage) < 0 )
  1059.            plbw->iVertScroll = 0;
  1060.            if ( plbw->iFocus > plbw->cLinesPage )
  1061.            plbw->iFocus = plbw->cLinesPage - 1L;
  1062.            }
  1063.                /* Check to see if there are more items within    */
  1064.                /* the list box than can be displayed which if    */
  1065.                /* the case, perform normal refresh        */
  1066.  
  1067.        if ( plbw->cItems > plbw->cLinesPage )
  1068.            RefreshList(plbw, (LONG)LONGFROMMP(mp1));
  1069.        else
  1070.                /* Check to see if the list box is being     */
  1071.                /* displayed                    */
  1072.  
  1073.            if ( WinIsWindowShowing(plbw->hWnd) )
  1074.            {
  1075.                /* List box is visible, need to refresh the    */
  1076.                /* list showing the item removed.  Form the    */
  1077.                /* rectangle based on the fact that the area    */
  1078.                /* that requires updating includes the former    */
  1079.                /* last line which is now blank.         */
  1080.  
  1081.            rcl = plbw->rcl;
  1082.            rcl.yTop = plbw->rcl.yTop - ((LONG)LONGFROMMP(mp1) - plbw->iVertScroll) * plbw->cyItem;
  1083.            if ( plbw->cItems < plbw->cLinesPage )
  1084.                rcl.yBottom = plbw->rcl.yTop - (plbw->cItems + 1) * plbw->cyItem;
  1085.            WinInvalidateRect(plbw->hWnd, &rcl, FALSE);
  1086.            UpdateScrollBars(plbw);
  1087.            }
  1088.            else
  1089.            plbw->fDirty = TRUE;
  1090.        }
  1091.        return(MRFROMLONG(plbw->cItems));
  1092.  
  1093.    /*********************************************************************/
  1094.    /*  Standard message:   LM_INSERTITEM                */
  1095.    /*               mp1 = MPFROMLONG(iItem);            */
  1096.    /*               mp2 = MPFROMP(pszText);            */
  1097.    /*********************************************************************/
  1098.  
  1099.    case LM_INSERTITEM :
  1100.                /* Determine if items exist within the list box    */
  1101.                /* in which case may need to resize the array    */
  1102.                /* the for list items otherwise will need to    */
  1103.                /* start the list off from scratch        */
  1104.  
  1105.        if ( plbw->cItems )
  1106.        {
  1107.                /* Existing list present, determine if the    */
  1108.                /* modulo boundary encountered in which case    */
  1109.                /* reallocate the list for a set of new entries. */
  1110.                /* The list is allocated in groups of 8, hence    */
  1111.                /* whenever the list total is a multiple of 8,    */
  1112.                /* the current list is full and needs to be    */
  1113.                /* expanded.                    */
  1114.  
  1115.        if ( (plbw->cItems % CBLK_LIST) == 0 )
  1116.            plbw->plc[0].apli = (PLISTITEM *)HeapRealloc(plbw->plc[0].hHeap, plbw->plc[0].apli,
  1117.                                 (((plbw->cItems / CBLK_LIST) + 1UL) * CBLK_LIST) *
  1118.                                 sizeof(PLISTITEM));
  1119.        }
  1120.        else
  1121.        {
  1122.                /* Starting off the list box from scratch,    */
  1123.                /* create the new heap that is to be used for    */
  1124.                /* list box                    */
  1125.  
  1126.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1127.  
  1128.                /* Allocate the memory needed for the control    */
  1129.                /* information and save the heap handle within    */
  1130.                /* it                        */
  1131.  
  1132.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1133.        plbw->plc[0].hHeap = hHeap;
  1134.  
  1135.                /* Allcoate memory for the initial start of the    */
  1136.                /* list.  The list is allocated in groups of 8,    */
  1137.                /* hence whenever the list total is a multiple    */
  1138.                /* of 8, the current list is full and needs to    */
  1139.                /* be expanded.                    */
  1140.  
  1141.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(hHeap, CBLK_LIST * sizeof(PLISTITEM));
  1142.        }
  1143.                /* Register exception handler that is used for    */
  1144.                /* the lazy pointer validation tests        */
  1145.  
  1146.        xcptregr.prev_structure     = NULL;
  1147.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1148.  
  1149.        DosSetExceptionHandler(&xcptregr);
  1150.  
  1151.        if ( setjmp(jBuf) )
  1152.        {
  1153.                /* Remove the exception handle since the lazy    */
  1154.                /* pointer evaluation is done            */
  1155.  
  1156.        DosUnsetExceptionHandler(&xcptregr);
  1157.        return(MRFROMLONG(TRUE));
  1158.        }
  1159.  
  1160.        plbw->plc[0].apli[plbw->cItems] = (PLISTITEM)HeapMalloc(plbw->plc[0].hHeap, sizeof(LISTITEM));
  1161.  
  1162.                /* Insert the item in the list based on the    */
  1163.                /* method of insertion                */
  1164.  
  1165.        switch ( (LONG)(SHORT)SHORT1FROMMP(mp1) )
  1166.        {
  1167.                /* Method:  Add to end of list box        */
  1168.        case LIT_END :
  1169.                /* Set the text of the item being inserted at    */
  1170.                /* the end of the list box list and check to see */
  1171.                /* if the item is wider than the rest in which    */
  1172.                /* case the maximum item width should be updated */
  1173.  
  1174.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[plbw->cItems++],
  1175.                   PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  1176.            plbw->cxItem = plbw->plc[0].apli[plbw->cItems - 1]->cxItem;
  1177.  
  1178.            RefreshList(plbw, plbw->cItems - 1);
  1179.            if ( plbw->fFocus && (plbw->iFocus == LIT_NONE) )
  1180.            SetFocus(plbw, 0L);
  1181.  
  1182.                /* Remove the exception handle since the lazy    */
  1183.                /* pointer evaluation is done            */
  1184.  
  1185.            DosUnsetExceptionHandler(&xcptregr);
  1186.            return(MRFROMLONG(plbw->cItems - 1));
  1187.  
  1188.                /* Method:  Add to list box in ascending order    */
  1189.                /* Method:  Add to list box in descending order    */
  1190.  
  1191.        case LIT_SORTASCENDING :
  1192.        case LIT_SORTDESCENDING :
  1193.  
  1194.                /* Set the text of the item being inserted at    */
  1195.                /* the end of the list box list and check to see */
  1196.                /* if the item is wider than the rest in which    */
  1197.                /* case the maximum item width should be updated */
  1198.  
  1199.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[plbw->cItems],
  1200.                   PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  1201.            plbw->cxItem = plbw->plc[0].apli[plbw->cItems]->cxItem;
  1202.  
  1203.            pli = plbw->plc[0].apli[plbw->cItems];
  1204.  
  1205.                /* Determine the type of sorting required    */
  1206.  
  1207.            if ( (LONG)LONGFROMMP(mp1) == LIT_SORTDESCENDING )
  1208.  
  1209.                /* Sort the list in descending order        */
  1210.  
  1211.            SortDescending(plbw->plc[0].apli, 0, plbw->cItems++);
  1212.            else
  1213.                /* Sort the list in ascending order        */
  1214.  
  1215.            SortAscending(plbw->plc[0].apli, 0, plbw->cItems++);
  1216.  
  1217.            for ( i = 0; i < plbw->cItems; i++ )
  1218.            if ( plbw->plc[0].apli[i] == pli )
  1219.                break;
  1220.            RefreshList(plbw, i);
  1221.            if ( plbw->fFocus && (plbw->iFocus == LIT_NONE) )
  1222.            SetFocus(plbw, 0L);
  1223.  
  1224.                /* Remove the exception handle since the lazy    */
  1225.                /* pointer evaluation is done            */
  1226.  
  1227.            DosUnsetExceptionHandler(&xcptregr);
  1228.            return(MRFROMLONG(i));
  1229.  
  1230.                /* Method: Add to list box in position indicated */
  1231.        default :
  1232.                /* Check to make sure that the item being    */
  1233.                /* inserted can be inserted in the position    */
  1234.                /* requested                    */
  1235.  
  1236.            if ( (LONGFROMMP(mp1) >= 0L) && (LONGFROMMP(mp1) <= plbw->cItems) )
  1237.            {
  1238.                /* Check to make sure that the item position is    */
  1239.                /* not the next logical entry at the end of the    */
  1240.                /* list                        */
  1241.  
  1242.            if ( LONGFROMMP(mp1) != plbw->cItems )
  1243.  
  1244.                /* Inserting the item somewhere within the list, */
  1245.                /* therefore open up the position for the entry    */
  1246.                /* in the correct location shifting the other    */
  1247.                /* entries down a position            */
  1248.  
  1249.                for ( i = plbw->cItems++; i > LONGFROMMP(mp1); i-- )
  1250.                plbw->plc[0].apli[i] = plbw->plc[0].apli[i - 1];
  1251.            else
  1252.                /* Entry position essentially the last one, just */
  1253.                /* bump the entries count since there is no need */
  1254.                /* to shuffle things around            */
  1255.  
  1256.                plbw->cItems++;
  1257.  
  1258.                /* Set the text of the item being inserted at    */
  1259.                /* the end of the list box list and check to see */
  1260.                /* if the item is wider than the rest in which    */
  1261.                /* case the maximum item width should be updated */
  1262.  
  1263.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[LONGFROMMP(mp1)],
  1264.                       PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  1265.                plbw->cxItem = plbw->plc[0].apli[LONGFROMMP(mp1)]->cxItem;
  1266.  
  1267.            RefreshList(plbw, (LONG)LONGFROMMP(mp1));
  1268.            if ( plbw->fFocus && (plbw->iFocus == LIT_NONE) )
  1269.                SetFocus(plbw, 0L);
  1270.  
  1271.                /* Remove the exception handle since the lazy    */
  1272.                /* pointer evaluation is done            */
  1273.  
  1274.            DosUnsetExceptionHandler(&xcptregr);
  1275.            return(MRFROMLONG(LONGFROMMP(mp1)));
  1276.            }
  1277.            else
  1278.            {
  1279.                /* Remove the exception handle since the lazy    */
  1280.                /* pointer evaluation is done            */
  1281.  
  1282.            DosUnsetExceptionHandler(&xcptregr);
  1283.            return(MRFROMLONG(LIT_ERROR));
  1284.            }
  1285.        }
  1286.  
  1287.    /*********************************************************************/
  1288.    /*  Standard message:   LM_QUERYITEMCOUNT                */
  1289.    /*               mp1 = 0L;                    */
  1290.    /*               mp2 = 0L;                    */
  1291.    /*********************************************************************/
  1292.  
  1293.    case LM_QUERYITEMCOUNT :
  1294.        return(MRFROMLONG(plbw->cItems));
  1295.  
  1296.    /*********************************************************************/
  1297.    /*  Standard message:   LM_QUERYITEMHANDLE                */
  1298.    /*               mp1 = MPFROMLONG(iItem);            */
  1299.    /*               mp2 = 0L;                    */
  1300.    /*********************************************************************/
  1301.  
  1302.    case LM_QUERYITEMHANDLE :
  1303.                /* Check to see that items within the list box    */
  1304.                /* and that the item requested is within the    */
  1305.                /* range of items                */
  1306.  
  1307.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1308.        return(MRFROMLONG(plbw->plc[0].apli[LONGFROMMP(mp1)]->ulHandle));
  1309.       break;
  1310.  
  1311.    /*********************************************************************/
  1312.    /*  Standard message:   LM_QUERYITEMTEXT                */
  1313.    /*               mp1 = MPFROM2SHORT(iItem, cch);        */
  1314.    /*               mp2 = MPFROMP(pszText);            */
  1315.    /*********************************************************************/
  1316.  
  1317.    case LM_QUERYITEMTEXT :
  1318.                /* Check to see that items within the list box    */
  1319.                /* and that the item requested is within the    */
  1320.                /* range of items                */
  1321.  
  1322.        if ( plbw->cItems && ((LONG)SHORT1FROMMP(mp1) < plbw->cItems) &&
  1323.         ((LONG)SHORT2FROMMP(mp1) > 0L) )
  1324.        {
  1325.        memcpy(PVOIDFROMMP(mp2), plbw->plc[0].apli[SHORT1FROMMP(mp1)]->pszText,
  1326.           (plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText + 1) < SHORT2FROMMP(mp1) ?
  1327.           (plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText + 1) :
  1328.           SHORT2FROMMP(mp1));
  1329.        return(MRFROMLONG(plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText < SHORT2FROMMP(mp1) ?
  1330.                  plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText :
  1331.                  SHORT2FROMMP(mp1)));
  1332.        }
  1333.        else
  1334.        return(0L);
  1335.  
  1336.    /*********************************************************************/
  1337.    /*  Standard message:   LM_QUERYITEMTEXTLENGTH            */
  1338.    /*               mp1 = MPFROMLONG(iItem);            */
  1339.    /*               mp2 = 0L;                    */
  1340.    /*********************************************************************/
  1341.  
  1342.    case LM_QUERYITEMTEXTLENGTH :
  1343.  
  1344.                /* Check to see that items within the list box    */
  1345.                /* and that the item requested is within the    */
  1346.                /* range of items                */
  1347.  
  1348.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1349.        return(MRFROMLONG(plbw->plc[0].apli[LONGFROMMP(mp1)]->cText));
  1350.        break;
  1351.  
  1352.    /*********************************************************************/
  1353.    /*  Standard message:   LM_QUERYSELECTION                */
  1354.    /*               mp1 = MPFROMLONG(iItemPrev);         */
  1355.    /*               mp2 = 0L;                    */
  1356.    /*********************************************************************/
  1357.  
  1358.    case LM_QUERYSELECTION :
  1359.        if ( plbw->cItems )
  1360.        if ( plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL) )
  1361.            {
  1362.            if ( (LONG)(SHORT)SHORT1FROMMP(mp1) == LIT_FIRST )
  1363.            {
  1364.            for ( i = 0; i < plbw->cItems; i++ )
  1365.                if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1366.                return(MRFROMLONG(i));
  1367.  
  1368.            return(MRFROMLONG(LIT_NONE));
  1369.            }
  1370.            else
  1371.            if ( (LONG)(SHORT)SHORT1FROMMP(mp1) >= 0L )
  1372.                {
  1373.                for ( i = (LONG)(SHORT)SHORT1FROMMP(mp1) + 1; i < plbw->cItems; i++ )
  1374.                if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1375.                    return(MRFROMLONG(i));
  1376.  
  1377.                return(MRFROMLONG(LIT_NONE));
  1378.                }
  1379.            else
  1380.                return(MRFROMLONG(LIT_NONE));
  1381.            }
  1382.        else
  1383.            return(MRFROMLONG(plbw->iSelected));
  1384.        else
  1385.        return(MRFROMLONG(LIT_NONE));
  1386.  
  1387.    /*********************************************************************/
  1388.    /*  Standard message:   LM_QUERYTOPINDEX                */
  1389.    /*               mp1 = 0L;                    */
  1390.    /*               mp2 = 0L;                    */
  1391.    /*********************************************************************/
  1392.  
  1393.    case LM_QUERYTOPINDEX :
  1394.        if ( plbw->cItems )
  1395.        return(MRFROMLONG(plbw->iVertScroll));
  1396.        else
  1397.        return(MRFROMLONG(LIT_NONE));
  1398.  
  1399.    /*********************************************************************/
  1400.    /*  Standard message:   LM_SEARCHSTRING                */
  1401.    /*               mp1 = MPFROM2SHORT(usCmd, iItem);        */
  1402.    /*               mp2 = MPFROMP(pszSearch);            */
  1403.    /*********************************************************************/
  1404.  
  1405.    case LM_SEARCHSTRING :
  1406.  
  1407.                /* Check to see that items within the list box    */
  1408.                /* and that the item requested is within the    */
  1409.                /* range of items                */
  1410.  
  1411.        if ( plbw->cItems && ((LONG)(SHORT)SHORT2FROMMP(mp1) < plbw->cItems) )
  1412.        {
  1413.                /* Check to make sure that valid values have    */
  1414.                /* been provided                 */
  1415.  
  1416.        if ( (((ULONG)SHORT1FROMMP(mp1) & (LSS_PREFIX | LSS_SUBSTRING)) == (LSS_PREFIX | LSS_SUBSTRING)) ||
  1417.         ((PSZ)PVOIDFROMMP(mp2) == NULL) )
  1418.            return(MRFROMLONG(LIT_ERROR));
  1419.  
  1420.                /* Set the starting index point            */
  1421.  
  1422.        if ( (LONG)(SHORT)SHORT2FROMMP(mp1) == LIT_FIRST )
  1423.            n = 0;
  1424.        else
  1425.            n = (LONG)(SHORT)SHORT2FROMMP(mp1) + 1;
  1426.  
  1427.                /* Check to see if the search is for the prefix    */
  1428.                /* portion of the list box item            */
  1429.  
  1430.        if ( (ULONG)SHORT1FROMMP(mp1) & LSS_PREFIX )
  1431.            {
  1432.            usLen = strlen((PSZ)PVOIDFROMMP(mp2));
  1433.  
  1434.            if ( (ULONG)SHORT1FROMMP(mp1) & LSS_CASESENSITIVE )
  1435.            {
  1436.            for ( i = n; i < plbw->cItems; i++ )
  1437.                if ( strncmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1438.                return(MRFROMLONG(i));
  1439.  
  1440.            for ( i = 0; i < n; i++ )
  1441.                if ( strncmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1442.                return(MRFROMLONG(i));
  1443.            }
  1444.            else
  1445.            {
  1446.            for ( i = n; i < plbw->cItems; i++ )
  1447.                if ( strnicmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1448.                return(MRFROMLONG(i));
  1449.  
  1450.            for ( i = 0; i < n; i++ )
  1451.                if ( strnicmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1452.                return(MRFROMLONG(i));
  1453.            }
  1454.            return(MRFROMLONG(LIT_NONE));
  1455.            }
  1456.        else
  1457.                /* Check to see if the search is for a substring */
  1458.                /* within the list box items            */
  1459.  
  1460.            if ( (ULONG)SHORT1FROMMP(mp1) & LSS_SUBSTRING )
  1461.            {
  1462.            for ( i = n; i < plbw->cItems; i++ )
  1463.                if ( strstr(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) )
  1464.                return(MRFROMLONG(i));
  1465.  
  1466.            for ( i = 0; i < n; i++ )
  1467.                if ( strstr(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) )
  1468.                return(MRFROMLONG(i));
  1469.  
  1470.            return(MRFROMLONG(LIT_NONE));
  1471.            }
  1472.            else
  1473.                /* Check to see if the search is case senstive    */
  1474.  
  1475.            if ( (ULONG)SHORT1FROMMP(mp1) & LSS_CASESENSITIVE )
  1476.                {
  1477.                for ( i = n; i < plbw->cItems; i++ )
  1478.                if ( strcmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1479.                    return(MRFROMLONG(i));
  1480.  
  1481.                for ( i = 0; i < n; i++ )
  1482.                if ( strcmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1483.                    return(MRFROMLONG(i));
  1484.  
  1485.                return(MRFROMLONG(LIT_NONE));
  1486.                }
  1487.            else
  1488.                /* Search is case insensitive            */
  1489.                {
  1490.                for ( i = n; i < plbw->cItems; i++ )
  1491.                if ( stricmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1492.                    return(MRFROMLONG(i));
  1493.  
  1494.                for ( i = 0; i < n; i++ )
  1495.                if ( stricmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1496.                    return(MRFROMLONG(i));
  1497.  
  1498.                return(MRFROMLONG(LIT_NONE));
  1499.                }
  1500.        }
  1501.        else
  1502.        return(MRFROMLONG(LIT_ERROR));
  1503.  
  1504.    /*********************************************************************/
  1505.    /*  Standard message:   LM_SELECTITEM                */
  1506.    /*               mp1 = MPFROMLONG(iItem);            */
  1507.    /*               mp2 = MPFROMLONG(fSelect);            */
  1508.    /*********************************************************************/
  1509.  
  1510.    case LM_SELECTITEM :
  1511.        if ( (LONG)LONGFROMMP(mp1) == LIT_NONE )
  1512.        {
  1513.        for ( i = 0; i < plbw->cItems; i++ )
  1514.            if (plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1515.            {
  1516.            SaveSelectState(0L, i);
  1517.            plbw->plc[0].apli[i]->fl &= ~LI_SELECTED;
  1518.  
  1519.                /* Invert the rectangle of the entry to return    */
  1520.                /* it back to its normal display colour        */
  1521.  
  1522.            DrawSelection(plbw, i);
  1523.            }
  1524.        return(MRFROMLONG(TRUE));
  1525.        }
  1526.        else
  1527.                /* Check to see that items within the list box    */
  1528.                /* and that the item requested is within the    */
  1529.                /* range of items                */
  1530.  
  1531.        if ( LONGFROMMP(mp1) < plbw->cItems )
  1532.            {
  1533.                /* Check to see if the list box allows for    */
  1534.                /* multiple selections                */
  1535.  
  1536.            if ( plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL) )
  1537.            {
  1538.                /* Multiple selections allowed, select or    */
  1539.                /* deselected the requested item         */
  1540.  
  1541.            SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1542.            if ( (BOOL)LONGFROMMP(mp2) )
  1543.                {
  1544.                RemoveFocus(plbw);
  1545.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl |= (LI_SELECTED | LI_FOCUS);
  1546.                FocusChange(plbw, plbw->iFocus = (LONG)LONGFROMMP(mp1), TRUE);
  1547.                if ( plbw->iSelected == -1 )
  1548.                plbw->iAnchor = plbw->iSelected = plbw->iFocus;
  1549.                }
  1550.            else
  1551.                {
  1552.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~LI_SELECTED;
  1553.                for ( i = (LONG)LONGFROMMP(mp1), plbw->iSelected = -1; i >= 0; i-- )
  1554.                if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1555.                    {
  1556.                    plbw->iSelected = i;
  1557.                    break;
  1558.                    }
  1559.  
  1560.                if ( plbw->iSelected == -1 )
  1561.                for ( i = (LONG)LONGFROMMP(mp1); i < plbw->cItems; i++ )
  1562.                    if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1563.                    {
  1564.                    plbw->iSelected = i;
  1565.                    break;
  1566.                    }
  1567.                }
  1568.                /* Invert the rectangle of the entry to return    */
  1569.                /* it back to its normal display colour        */
  1570.  
  1571.            DrawSelection(plbw, (LONG)LONGFROMMP(mp1));
  1572.            }
  1573.            else
  1574.            {
  1575.                /* Single selection only allowed for the list    */
  1576.                /* box, deselect the previous item and then    */
  1577.                /* select the desired one            */
  1578.  
  1579.            if ( (BOOL)LONGFROMMP(mp2) )
  1580.                {
  1581.                if ( plbw->iSelected != LIT_NONE )
  1582.                {
  1583.                SaveSelectState(0L, plbw->iSelected);
  1584.                plbw->plc[0].apli[plbw->iSelected]->fl &= ~(LI_SELECTED | LI_FOCUS);
  1585.  
  1586.                /* Invert the rectangle of the entry to return    */
  1587.                /* it back to its normal display colour        */
  1588.  
  1589.                DrawSelection(plbw, plbw->iSelected);
  1590.                }
  1591.                SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1592.                plbw->plc[0].apli[plbw->iFocus = plbw->iSelected = (LONG)LONGFROMMP(mp1)]->fl |= (LI_SELECTED | LI_FOCUS);
  1593.                }
  1594.            else
  1595.                {
  1596.                SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1597.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~(LI_SELECTED | LI_FOCUS);
  1598.                plbw->iSelected = plbw->iFocus = LIT_NONE;
  1599.                }
  1600.                /* Determine if the selected item should be    */
  1601.                /* centred within the list making sure that    */
  1602.                /* this only occurs when item is not in the last */
  1603.                /* page of the list box or when the list box is    */
  1604.                /* less than a full page             */
  1605.  
  1606.            if ( plbw->cItems < plbw->cLinesPage )
  1607.                iVertScroll = plbw->iVertScroll;
  1608.            else
  1609.                if ( (iVertScroll = plbw->iFocus - plbw->cLinesPage / 2L) < 0L )
  1610.                iVertScroll = 0L;
  1611.                else
  1612.                if ( iVertScroll > (plbw->cItems - plbw->cLinesPage) )
  1613.                    iVertScroll = plbw->cItems - plbw->cLinesPage;
  1614.  
  1615.            if ( plbw->iVertScroll != iVertScroll )
  1616.                {
  1617.                RefreshList(plbw, plbw->iVertScroll = iVertScroll);
  1618.                mrNotifyOwner(plbw, LN_SCROLL);
  1619.                }
  1620.            else
  1621.                if ( plbw->iSelected != LIT_NONE )
  1622.                DrawSelection(plbw, plbw->iSelected);
  1623.            if ( LONGFROMMP(mp1) )
  1624.                FocusChange(plbw, (LONG)LONGFROMMP(mp1), TRUE);
  1625.            }
  1626.            mrNotifyOwner(plbw, LN_SELECT);
  1627.            return(MRFROMLONG(TRUE));
  1628.            }
  1629.        else
  1630.            return(MRFROMLONG(FALSE));
  1631.  
  1632.    /*********************************************************************/
  1633.    /*  Standard message:   LM_SETITEMHANDLE                */
  1634.    /*               mp1 = MPFROMLONG(iItem);            */
  1635.    /*               mp2 = MPFROMLONG(ulHandle);            */
  1636.    /*********************************************************************/
  1637.  
  1638.    case LM_SETITEMHANDLE :
  1639.  
  1640.                /* Check to see that items within the list box    */
  1641.                /* and that the item requested is within the    */
  1642.                /* range of items                */
  1643.  
  1644.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1645.        {
  1646.        plbw->plc[0].apli[LONGFROMMP(mp1)]->ulHandle = (ULONG)LONGFROMMP(mp2);
  1647.        return(MRFROMLONG(TRUE));
  1648.        }
  1649.        break;
  1650.  
  1651.    /*********************************************************************/
  1652.    /*  Standard message:   LM_SETITEMHEIGHT                */
  1653.    /*               mp1 = MPFROMLONG(lHeight);            */
  1654.    /*               mp2 = 0L                    */
  1655.    /*********************************************************************/
  1656.  
  1657.    case LM_SETITEMHEIGHT :
  1658.        if ( LONGFROMMP(mp1) > 0L )
  1659.        {
  1660.        plbw->cyItem = (LONG)LONGFROMMP(mp1);
  1661.        SizeListBox(plbw);
  1662.        return(MRFROMLONG(TRUE));
  1663.        }
  1664.        break;
  1665.  
  1666.    /*********************************************************************/
  1667.    /*  Standard message:   LM_SETITEMTEXT                */
  1668.    /*               mp1 = MPFROMLONG(iItem);            */
  1669.    /*               mp2 = MPFROMP(pszText);            */
  1670.    /*********************************************************************/
  1671.  
  1672.    case LM_SETITEMTEXT :
  1673.                /* Check to see that items within the list box    */
  1674.                /* and that the item requested is within the    */
  1675.                /* range of items                */
  1676.  
  1677.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) && PVOIDFROMMP(mp2) )
  1678.        {
  1679.                /* Register exception handler that is used for    */
  1680.                /* the lazy pointer validation tests        */
  1681.  
  1682.        xcptregr.prev_structure   = NULL;
  1683.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1684.  
  1685.        DosSetExceptionHandler(&xcptregr);
  1686.  
  1687.        if ( setjmp(jBuf) )
  1688.            {
  1689.                /* Remove the exception handle since the lazy    */
  1690.                /* pointer evaluation is done            */
  1691.  
  1692.            DosUnsetExceptionHandler(&xcptregr);
  1693.            return(MRFROMLONG(TRUE));
  1694.            }
  1695.        HeapFree(plbw->plc[0].hHeap, plbw->plc[0].apli[LONGFROMMP(mp1)]->pszText);
  1696.        if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[LONGFROMMP(mp1)],
  1697.                   PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle & LS_OWNERDRAW) )
  1698.            plbw->cxItem = plbw->plc[0].apli[LONGFROMMP(mp1)]->cxItem;
  1699.  
  1700.                /* Remove the exception handle since the lazy    */
  1701.                /* pointer evaluation is done            */
  1702.  
  1703.        DosUnsetExceptionHandler(&xcptregr);
  1704.        return(MRFROMLONG(TRUE));
  1705.        }
  1706.        break;
  1707.  
  1708.    /*********************************************************************/
  1709.    /*  Standard message:   LM_SETTOPINDEX                */
  1710.    /*               mp1 = MPFROMLONG(item);            */
  1711.    /*               mp2 = 0L                    */
  1712.    /*********************************************************************/
  1713.  
  1714.    case LM_SETTOPINDEX :
  1715.                /* Check to see that items within the list box    */
  1716.                /* and that the item requested is within the    */
  1717.                /* range of items                */
  1718.  
  1719.        if ( plbw->cItems && (LONGFROMMP(mp1) > 0) )
  1720.        {
  1721.        if ( LONGFROMMP(mp1) < plbw->cItems    )
  1722.            if ( plbw->cItems > plbw->cLinesPage )
  1723.            if ( LONGFROMMP(mp1) > (plbw->cItems - plbw->cLinesPage) )
  1724.                plbw->iVertScroll = plbw->cItems - plbw->cLinesPage;
  1725.            else
  1726.                if ( plbw->cItems <= plbw->cLinesPage )
  1727.                plbw->iVertScroll = 0L;
  1728.                else
  1729.                plbw->iVertScroll = (LONG)LONGFROMMP(mp1);
  1730.            else
  1731.            plbw->iVertScroll = 0L;
  1732.        else
  1733.            plbw->iVertScroll = 0L;
  1734.  
  1735.        return(MRFROMLONG(TRUE));
  1736.        }
  1737.  
  1738.        break;
  1739.    }
  1740. return(0L);
  1741. }
  1742. #pragma subtitle("   List Manager - Extended List Box Messages Procedure")
  1743. #pragma page( )
  1744.  
  1745. /* --- mrExtendedListHandler --------------------------- [ Public ] --- */
  1746. /*                                    */
  1747. /*     This function is used to process the extended messages for the    */
  1748. /*     list box control window.                     */
  1749. /*                                    */
  1750. /*     Upon Entry:                            */
  1751. /*                                    */
  1752. /*     HWND   hWnd; = Window Handle                    */
  1753. /*     ULONG  msg;  = PM Message                    */
  1754. /*     MPARAM mp1;  = Message Parameter 1                */
  1755. /*     MPARAM mp2;  = Message Parameter 2                */
  1756. /*                                    */
  1757. /*     Upon Exit:                            */
  1758. /*                                    */
  1759. /*     mrExtendedListHandler = Message Handling Result            */
  1760. /*                                    */
  1761. /* -------------------------------------------------------------------- */
  1762.  
  1763. MRESULT EXPENTRY mrExtendedListHandler(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1764.  
  1765. {
  1766. HHEAPMEM     hHeap;           /* Heap Handle            */
  1767. PLISTITEM    albi;           /* List Box Item Input Pointer    */
  1768. PLISTBOXWIN  plbw;           /* List Box Internal Data Pointer    */
  1769. PSZ         *apsz;           /* String Array Pointer        */
  1770. PULONG         aul;           /* Handle Array Pointer        */
  1771. register INT i, n;           /* Loop Counter            */
  1772. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception Record        */
  1773.  
  1774. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1775.  
  1776. switch ( msg )
  1777.    {
  1778.  
  1779.    /*********************************************************************/
  1780.    /*  Extended message:   LMX_ADDARRAY                 */
  1781.    /*               mp1 = MPFROMLONG(cItems);            */
  1782.    /*               mp2 = MPFROMP(apsz);             */
  1783.    /*********************************************************************/
  1784.  
  1785.    case LMX_ADDARRAY :
  1786.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  1787.        {
  1788.                /* Check to see if any items within the list box */
  1789.                /* which if there are none, there is nothing to    */
  1790.                /* delete and there is no memory to release    */
  1791.  
  1792.        if ( plbw->cItems == 0 )
  1793.            {
  1794.                /* Starting off the list box from scratch,    */
  1795.                /* create the new heap that is to be used for    */
  1796.                /* list box                    */
  1797.  
  1798.            hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1799.  
  1800.                /* Allocate the memory needed for the control    */
  1801.                /* information and save the heap handle within    */
  1802.                /* it                        */
  1803.  
  1804.            plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1805.  
  1806.                /* Allocate memory for the initial start of the    */
  1807.                /* list.  The list is allocated in groups of 8,    */
  1808.                /* hence whenever the list total is a multiple    */
  1809.                /* of 8, the current list is full and needs to    */
  1810.                /* be expanded.                    */
  1811.  
  1812.            plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  1813.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) * CBLK_LIST) *
  1814.                                sizeof(PLISTITEM *));
  1815.            }
  1816.        else
  1817.            plbw->plc[0].apli = (PLISTITEM *)HeapRealloc(plbw->plc[0].hHeap, plbw->plc[0].apli,
  1818.                                 ((((LONGFROMMP(mp1) + plbw->cItems) / CBLK_LIST) + 1UL) * CBLK_LIST) *
  1819.                                 sizeof(PLISTITEM *));
  1820.  
  1821.                /* Register exception handler that is used for    */
  1822.                /* the lazy pointer validation tests        */
  1823.  
  1824.        xcptregr.prev_structure   = NULL;
  1825.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1826.  
  1827.        DosSetExceptionHandler(&xcptregr);
  1828.  
  1829.        if ( setjmp(jBuf) )
  1830.            {
  1831.            HeapRelease(hHeap);
  1832.  
  1833.                /* Remove the exception handle since the lazy    */
  1834.                /* pointer evaluation is done            */
  1835.  
  1836.            DosUnsetExceptionHandler(&xcptregr);
  1837.            return(MRFROMLONG(TRUE));
  1838.            }
  1839.                /* Get the pointer to the item array        */
  1840.  
  1841.        apsz = (PSZ *)PVOIDFROMMP(mp2);
  1842.  
  1843.                /* Loop through the list of items and place each */
  1844.                /* one within the list box.  If the list box    */
  1845.                /* contains any items, append the new items to    */
  1846.                /* the end of the list.                */
  1847.  
  1848.        for ( i = 0, n = plbw->cItems; i < LONGFROMMP(mp1); i++, n++ )
  1849.            {
  1850.            plbw->plc[0].apli[n] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  1851.            if ( apsz[i] == NULL )
  1852.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[n], "") ;
  1853.            else
  1854.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[n],
  1855.                       apsz[i]) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  1856.                plbw->cxItem = plbw->plc[0].apli[n]->cxItem;
  1857.            }
  1858.                /* Save the list box length and refresh the    */
  1859.                /* list box                    */
  1860.  
  1861.        plbw->cItems += (LONG)LONGFROMMP(mp1);
  1862.        RefreshList(plbw, 0L);
  1863.  
  1864.                /* Remove the exception handle since the lazy    */
  1865.                /* pointer evaluation is done            */
  1866.  
  1867.        DosUnsetExceptionHandler(&xcptregr);
  1868.        }
  1869.        else
  1870.        return(MRFROMLONG(TRUE));
  1871.        break;
  1872.  
  1873.    /*********************************************************************/
  1874.    /*  Extended message:   LMX_CALCSIZE                 */
  1875.    /*               mp1 = MPFROMLONG(cLines);            */
  1876.    /*               mp2 = 0L;                    */
  1877.    /*********************************************************************/
  1878.  
  1879.    case LMX_CALCSIZE :
  1880.        if ( LONGFROMMP(mp1) > 0L )
  1881.        if ( plbw->flStyle & LS_NOADJUSTPOS )
  1882.            return(MRFROMLONG(MAKELONG(plbw->cx, plbw->cy)));
  1883.        else
  1884.            return(MRFROMLONG(MAKELONG(plbw->cx,
  1885.                       LONGFROMMP(mp1) * plbw->cyItem + 2L +
  1886.                       (plbw->flStyle & LS_HORZSCROLL ? plbw->cyScroll : 2L))));
  1887.        break;
  1888.  
  1889.    /*********************************************************************/
  1890.    /*  Extended message:   LMX_CALCLINECOUNT                */
  1891.    /*               mp1 = MPFROMLONG(lHeight);            */
  1892.    /*               mp2 = 0L;                    */
  1893.    /*********************************************************************/
  1894.  
  1895.    case LMX_CALCLINECOUNT :
  1896.        if ( LONGFROMMP(mp1) > 0L )
  1897.        return(MRFROMLONG((LONGFROMMP(mp1) - (2L +
  1898.                   (plbw->flStyle & LS_HORZSCROLL ? plbw->cyScroll : 2L))) /
  1899.                   plbw->cyItem));
  1900.        break;
  1901.  
  1902.    /*********************************************************************/
  1903.    /*  Extended message:   LMX_SETITEMCOUNT                */
  1904.    /*               mp1 = MPFROMLONG(cItems);            */
  1905.    /*               mp2 = 0L;                    */
  1906.    /*********************************************************************/
  1907.  
  1908.    case LMX_SETITEMCOUNT :
  1909.        if ( LONGFROMMP(mp1) > 0L )
  1910.        {
  1911.                /* Check to see if any items within the list box */
  1912.                /* which if there are none, there is nothing to    */
  1913.                /* delete and there is no memory to release    */
  1914.  
  1915.        if ( plbw->cItems )
  1916.            {
  1917.                /* Release the heap associated with the list box */
  1918.                /* items and set the item count to zero        */
  1919.  
  1920.            HeapRelease(plbw->plc[0].hHeap);
  1921.  
  1922.            plbw->cHorzScroll =
  1923.            plbw->cVertScroll =
  1924.            plbw->iHorzScroll =
  1925.            plbw->iVertScroll = 0L;
  1926.            plbw->cItems = 0UL;
  1927.            plbw->iFocus = plbw->iSelected = LIT_NONE;
  1928.            }
  1929.                /* Starting off the list box from scratch,    */
  1930.                /* create the new heap that is to be used for    */
  1931.                /* list box                    */
  1932.  
  1933.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1934.  
  1935.                /* Allocate the memory needed for the control    */
  1936.                /* information and save the heap handle within    */
  1937.                /* it                        */
  1938.  
  1939.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1940.  
  1941.                /* Allocate memory for the initial start of the    */
  1942.                /* list.  The list is allocated in groups of 8,    */
  1943.                /* hence whenever the list total is a multiple    */
  1944.                /* of 8, the current list is full and needs to    */
  1945.                /* be expanded.                    */
  1946.  
  1947.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  1948.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) * CBLK_LIST) *
  1949.                                sizeof(PLISTITEM));
  1950.  
  1951.        for ( i = 0; i < (INT)LONGFROMMP(mp1); i++ )
  1952.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  1953.  
  1954.        plbw->cItems = (LONG)LONGFROMMP(mp1);
  1955.        RefreshList(plbw, 0L);
  1956.        }
  1957.        else
  1958.        return(MRFROMLONG(TRUE));
  1959.        break;
  1960.  
  1961.    /*********************************************************************/
  1962.    /*  Extended message:   LMX_SETARRAY                 */
  1963.    /*               mp1 = MPFROMLONG(cItems);            */
  1964.    /*               mp2 = MPFROMP(apsz);             */
  1965.    /*********************************************************************/
  1966.  
  1967.    case LMX_SETARRAY :
  1968.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  1969.        {
  1970.                /* Check to see if any items within the list box */
  1971.                /* which if there are none, there is nothing to    */
  1972.                /* delete and there is no memory to release    */
  1973.  
  1974.        if ( plbw->cItems )
  1975.            {
  1976.                /* Release the heap associated with the list box */
  1977.                /* items and set the item count to zero        */
  1978.  
  1979.            HeapRelease(plbw->plc[0].hHeap);
  1980.  
  1981.            FocusChange(plbw, plbw->iFocus, FALSE);
  1982.            plbw->iFocus = plbw->iSelected = LIT_NONE;
  1983.            plbw->cHorzScroll =
  1984.            plbw->cVertScroll =
  1985.            plbw->iHorzScroll =
  1986.            plbw->iVertScroll = 0L;
  1987.            plbw->cItems = 0UL;
  1988.            }
  1989.                /* Register exception handler that is used for    */
  1990.                /* the lazy pointer validation tests        */
  1991.  
  1992.        xcptregr.prev_structure   = NULL;
  1993.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1994.  
  1995.        DosSetExceptionHandler(&xcptregr);
  1996.  
  1997.        if ( setjmp(jBuf) )
  1998.            {
  1999.            HeapRelease(hHeap);
  2000.  
  2001.                /* Remove the exception handle since the lazy    */
  2002.                /* pointer evaluation is done            */
  2003.  
  2004.            DosUnsetExceptionHandler(&xcptregr);
  2005.            return(MRFROMLONG(TRUE));
  2006.            }
  2007.                /* Starting off the list box from scratch,    */
  2008.                /* create the new heap that is to be used for    */
  2009.                /* list box                    */
  2010.  
  2011.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  2012.  
  2013.                /* Allocate the memory needed for the control    */
  2014.                /* information and save the heap handle within    */
  2015.                /* it                        */
  2016.  
  2017.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  2018.  
  2019.                /* Allocate memory for the initial start of the    */
  2020.                /* list.  The list is allocated in groups of 8,    */
  2021.                /* hence whenever the list total is a multiple    */
  2022.                /* of 8, the current list is full and needs to    */
  2023.                /* be expanded.                    */
  2024.  
  2025.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  2026.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) * CBLK_LIST) *
  2027.                                sizeof(PLISTITEM *));
  2028.  
  2029.                /* Get the pointer to the item array        */
  2030.  
  2031.        apsz = (PSZ *)PVOIDFROMMP(mp2);
  2032.  
  2033.                /* Loop through the list of items and place each */
  2034.                /* one within the list box.  If the list box    */
  2035.                /* contains any items, append the new items to    */
  2036.                /* the end of the list.                */
  2037.  
  2038.        for ( i = 0; i < LONGFROMMP(mp1); i++ )
  2039.            {
  2040.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  2041.            if ( apsz[i] == NULL )
  2042.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i], "") ;
  2043.            else
  2044.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i],
  2045.                       apsz[i]) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  2046.                plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  2047.            }
  2048.                /* Save the list box length and refresh the    */
  2049.                /* list box                    */
  2050.  
  2051.        plbw->cItems += (LONG)LONGFROMMP(mp1);
  2052.        RefreshList(plbw, 0L);
  2053.  
  2054.                /* Remove the exception handle since the lazy    */
  2055.                /* pointer evaluation is done            */
  2056.  
  2057.        DosUnsetExceptionHandler(&xcptregr);
  2058.        }
  2059.        else
  2060.        return(MRFROMLONG(TRUE));
  2061.        break;
  2062.  
  2063.    /*********************************************************************/
  2064.    /*  Extended message:   LMX_SETARRAY                 */
  2065.    /*               mp1 = MPFROMLONG(cItems);            */
  2066.    /*               mp2 = MPFROMP(aul);                */
  2067.    /*********************************************************************/
  2068.  
  2069.    case LMX_SETARRAYHANDLES :
  2070.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2071.        {
  2072.        if ( LONGFROMMP(mp1) > plbw->cItems )
  2073.            return(MRFROMLONG(TRUE));
  2074.  
  2075.                /* Register exception handler that is used for    */
  2076.                /* the lazy pointer validation tests        */
  2077.  
  2078.        xcptregr.prev_structure   = NULL;
  2079.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2080.  
  2081.        DosSetExceptionHandler(&xcptregr);
  2082.  
  2083.        if ( setjmp(jBuf) )
  2084.            {
  2085.                /* Remove the exception handle since the lazy    */
  2086.                /* pointer evaluation is done            */
  2087.  
  2088.            DosUnsetExceptionHandler(&xcptregr);
  2089.            return(MRFROMLONG(TRUE));
  2090.            }
  2091.                /* Get the pointer to the item array        */
  2092.  
  2093.        aul = (PULONG)PVOIDFROMMP(mp2);
  2094.  
  2095.                /* Loop through the list of items and place each */
  2096.                /* one within the list box.  If the list box    */
  2097.                /* contains any items, append the new items to    */
  2098.                /* the end of the list.                */
  2099.  
  2100.        for ( i = 0; i < LONGFROMMP(mp1); i++ )
  2101.            plbw->plc[0].apli[i]->ulHandle = aul[i];
  2102.  
  2103.                /* Remove the exception handle since the lazy    */
  2104.                /* pointer evaluation is done            */
  2105.  
  2106.        DosUnsetExceptionHandler(&xcptregr);
  2107.        }
  2108.        else
  2109.        return(MRFROMLONG(TRUE));
  2110.        break;
  2111.  
  2112.    /*********************************************************************/
  2113.    /*  Extended message:   LMX_SETARRAYITEMS                */
  2114.    /*               mp1 = MPFROMLONG(cItems);            */
  2115.    /*               mp2 = MPFROMP(lbi);                */
  2116.    /*********************************************************************/
  2117.  
  2118.    case LMX_SETARRAYITEMS :
  2119.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2120.        {
  2121.                /* Check to see if any items within the list box */
  2122.                /* which if there are none, there is nothing to    */
  2123.                /* delete and there is no memory to release    */
  2124.  
  2125.        if ( plbw->cItems )
  2126.            {
  2127.                /* Release the heap associated with the list box */
  2128.                /* items and set the item count to zero        */
  2129.  
  2130.            HeapRelease(plbw->plc[0].hHeap);
  2131.  
  2132.            FocusChange(plbw, plbw->iFocus, FALSE);
  2133.            plbw->iFocus = plbw->iSelected = LIT_NONE;
  2134.            plbw->cHorzScroll =
  2135.            plbw->cVertScroll =
  2136.            plbw->iHorzScroll =
  2137.            plbw->iVertScroll = 0L;
  2138.            plbw->cItems = 0UL;
  2139.            }
  2140.                /* Register exception handler that is used for    */
  2141.                /* the lazy pointer validation tests        */
  2142.  
  2143.        xcptregr.prev_structure   = NULL;
  2144.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2145.  
  2146.        DosSetExceptionHandler(&xcptregr);
  2147.  
  2148.        if ( setjmp(jBuf) )
  2149.            {
  2150.            HeapRelease(hHeap);
  2151.  
  2152.                /* Remove the exception handle since the lazy    */
  2153.                /* pointer evaluation is done            */
  2154.  
  2155.            DosUnsetExceptionHandler(&xcptregr);
  2156.            return(MRFROMLONG(TRUE));
  2157.            }
  2158.                /* Starting off the list box from scratch,    */
  2159.                /* create the new heap that is to be used for    */
  2160.                /* list box                    */
  2161.  
  2162.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  2163.  
  2164.                /* Allocate the memory needed for the control    */
  2165.                /* information and save the heap handle within    */
  2166.                /* it                        */
  2167.  
  2168.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  2169.  
  2170.                /* Allocate memory for the initial start of the    */
  2171.                /* list.  The list is allocated in groups of 8,    */
  2172.                /* hence whenever the list total is a multiple    */
  2173.                /* of 8, the current list is full and needs to    */
  2174.                /* be expanded.                    */
  2175.  
  2176.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  2177.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) * CBLK_LIST) *
  2178.                                sizeof(PLISTITEM *));
  2179.  
  2180.                /* Get the pointer to the item array        */
  2181.  
  2182.        albi = (PLISTITEM)PVOIDFROMMP(mp2);
  2183.  
  2184.                /* Loop through the list of items and place each */
  2185.                /* one within the list box.  If the list box    */
  2186.                /* contains any items, append the new items to    */
  2187.                /* the end of the list.                */
  2188.  
  2189.        for ( i = 0; i < LONGFROMMP(mp1); i++ )
  2190.            {
  2191.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  2192.  
  2193.            if ( albi[i].pszText == NULL )
  2194.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i], "") ;
  2195.            else
  2196.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i],
  2197.                       albi[i].pszText) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  2198.                plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  2199.  
  2200.            plbw->plc[0].apli[i]->ulHandle = albi[i].ulHandle;
  2201.            }
  2202.                /* Save the list box length and refresh the    */
  2203.                /* list box                    */
  2204.  
  2205.        plbw->cItems += (LONG)LONGFROMMP(mp1);
  2206.        RefreshList(plbw, 0L);
  2207.  
  2208.                /* Remove the exception handle since the lazy    */
  2209.                /* pointer evaluation is done            */
  2210.  
  2211.        DosUnsetExceptionHandler(&xcptregr);
  2212.        }
  2213.        else
  2214.        return(MRFROMLONG(TRUE));
  2215.        break;
  2216.  
  2217.    /*********************************************************************/
  2218.    /*  Extended message:   LMX_SORT                    */
  2219.    /*               mp1 = MPFROMLONG(lDirection);        */
  2220.    /*               mp2 = 0L;                    */
  2221.    /*********************************************************************/
  2222.  
  2223.    case LMX_SORT :
  2224.        switch ( LONGFROMMP(mp1) )
  2225.        {
  2226.        case LIT_SORTASCENDING :
  2227.            if ( plbw->cItems )
  2228.  
  2229.                /* Sort the list in ascending order        */
  2230.  
  2231.            SortAscending(plbw->plc[0].apli, 0, plbw->cItems - 1);
  2232.            break;
  2233.  
  2234.        case LIT_SORTDESCENDING :
  2235.            if ( plbw->cItems )
  2236.  
  2237.                /* Sort the list in descending order        */
  2238.  
  2239.            SortDescending(plbw->plc[0].apli, 0, plbw->cItems - 1);
  2240.            break;
  2241.  
  2242.        default :
  2243.            return(MRFROMLONG(TRUE));
  2244.        }
  2245.        break;
  2246.  
  2247.    /*********************************************************************/
  2248.    /*  Extended message:   LMX_SELECTALL                */
  2249.    /*               mp1 = 0L;                    */
  2250.    /*               mp2 = 0L;                    */
  2251.    /*********************************************************************/
  2252.  
  2253.    case LMX_SELECTALL :
  2254.        if ( plbw->cItems && (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL)) )
  2255.        {
  2256.        for ( i = 0; i < plbw->cItems; i++ )
  2257.            if ( (plbw->plc[0].apli[i]->fl & LI_SELECTED) == 0UL )
  2258.            {
  2259.            SaveSelectState(0L, i);
  2260.            plbw->plc[0].apli[i]->fl |= LI_SELECTED;
  2261.            }
  2262.        mrNotifyOwner(plbw, LN_SELECT);
  2263.        RefreshList(plbw, 0L);
  2264.        }
  2265.        else
  2266.        return(MRFROMLONG(TRUE));
  2267.        break;
  2268.  
  2269.    /*********************************************************************/
  2270.    /*  Extended message:   LMX_QUERYITEMCOUNT                */
  2271.    /*               mp1 = 0L;                    */
  2272.    /*               mp2 = 0L;                    */
  2273.    /*********************************************************************/
  2274.  
  2275.    case LMX_QUERYITEMCOUNT :
  2276.        return(MRFROMLONG(plbw->cItems));
  2277.    }
  2278. return(0L);
  2279. }
  2280. #pragma subtitle("   List Manager - Extended List Box Messages Procedure")
  2281. #pragma page( )
  2282.  
  2283. /* --- mrChkBoxHandler --------------------------------- [ Public ] --- */
  2284. /*                                    */
  2285. /*     This function is used to process the extended messages for the    */
  2286. /*     list box control window check box support.            */
  2287. /*                                    */
  2288. /*     Upon Entry:                            */
  2289. /*                                    */
  2290. /*     HWND   hWnd; = Window Handle                    */
  2291. /*     ULONG  msg;  = PM Message                    */
  2292. /*     MPARAM mp1;  = Message Parameter 1                */
  2293. /*     MPARAM mp2;  = Message Parameter 2                */
  2294. /*                                    */
  2295. /*     Upon Exit:                            */
  2296. /*                                    */
  2297. /*     mrChkBoxHandler = Message Handling Result            */
  2298. /*                                    */
  2299. /* -------------------------------------------------------------------- */
  2300.  
  2301. MRESULT EXPENTRY mrChkBoxHandler(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  2302.  
  2303. {
  2304. PBOOL         afl;           /* Flags Array            */
  2305. PLISTBOXWIN  plbw;           /* List Box Internal Data Pointer    */
  2306. register INT i, n;           /* Loop Counter            */
  2307. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception Record        */
  2308.  
  2309. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2310.  
  2311. switch ( msg )
  2312.    {
  2313.  
  2314.    /*********************************************************************/
  2315.    /*  Extended message:   LMX_ADDARRAY                 */
  2316.    /*               mp1 = MPFROMLONG(iItem);            */
  2317.    /*               mp2 = MPFROMLONG(fSelect);            */
  2318.    /*********************************************************************/
  2319.  
  2320.    case LMX_SETCHECK :
  2321.        if ( (LONG)LONGFROMMP(mp1) == LIT_NONE )
  2322.        {
  2323.        for ( i = 0; i < plbw->cItems; i++ )
  2324.            if (plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2325.            {
  2326.            SaveSelectState(0L, i);
  2327.            plbw->plc[0].apli[i]->fl &= ~LI_CHECKED;
  2328.  
  2329.                /* Invert the rectangle of the entry to return    */
  2330.                /* it back to its normal display colour        */
  2331.  
  2332.            DrawSelection(plbw, i);
  2333.            }
  2334.        return(MRFROMLONG(TRUE));
  2335.        }
  2336.        else
  2337.                /* Check to see that items within the list box    */
  2338.                /* and that the item requested is within the    */
  2339.                /* range of items                */
  2340.  
  2341.        if ( (LONG)LONGFROMMP(mp1) < plbw->cItems )
  2342.            {
  2343.            if ( plbw->plc[0].apli[LONGFROMMP(mp1)]->fl & LI_CHECKED )
  2344.            plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~LI_CHECKED;
  2345.            else
  2346.            plbw->plc[0].apli[LONGFROMMP(mp1)]->fl |= LI_CHECKED;
  2347.  
  2348.                /* Draw the updated item             */
  2349.  
  2350.            DrawSelection(plbw, (LONG)LONGFROMMP(mp1));
  2351.            mrNotifyOwner(plbw, LNX_CHECKED);
  2352.            return(MRFROMLONG(TRUE));
  2353.            }
  2354.        else
  2355.            return(MRFROMLONG(FALSE));
  2356.  
  2357.    /*********************************************************************/
  2358.    /*  Extended message:   LMX_QUERYCHECK                */
  2359.    /*               mp1 = MPFROMLONG(iItemPrev);         */
  2360.    /*               mp2 = 0L;                    */
  2361.    /*********************************************************************/
  2362.  
  2363.    case LMX_QUERYCHECK :
  2364.        if ( plbw->cItems )
  2365.        {
  2366.        if ( (LONG)(SHORT)SHORT1FROMMP(mp1) == LIT_FIRST )
  2367.            {
  2368.            for ( i = 0; i < plbw->cItems; i++ )
  2369.            if ( plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2370.                return(MRFROMLONG(i));
  2371.  
  2372.            return(MRFROMLONG(LIT_NONE));
  2373.            }
  2374.        else
  2375.            if ( (LONG)(SHORT)SHORT1FROMMP(mp1) >= 0L )
  2376.            {
  2377.            for ( i = (LONG)(SHORT)SHORT1FROMMP(mp1) + 1; i < plbw->cItems; i++ )
  2378.                if ( plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2379.                return(MRFROMLONG(i));
  2380.  
  2381.            return(MRFROMLONG(LIT_NONE));
  2382.            }
  2383.            else
  2384.            return(MRFROMLONG(LIT_NONE));
  2385.        }
  2386.        else
  2387.        return(MRFROMLONG(LIT_NONE));
  2388.  
  2389.    /*********************************************************************/
  2390.    /*  Extended message:   LMX_SETCHECKARRAY                */
  2391.    /*               mp1 = MPFROMLONG(cItems);            */
  2392.    /*               mp2 = MPFROMP(afl);                */
  2393.    /*********************************************************************/
  2394.  
  2395.    case LMX_SETCHECKARRAY :
  2396.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2397.        {
  2398.                /* Register exception handler that is used for    */
  2399.                /* the lazy pointer validation tests        */
  2400.  
  2401.        xcptregr.prev_structure   = NULL;
  2402.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2403.  
  2404.        DosSetExceptionHandler(&xcptregr);
  2405.  
  2406.        if ( setjmp(jBuf) )
  2407.            {
  2408.                /* Remove the exception handle since the lazy    */
  2409.                /* pointer evaluation is done            */
  2410.  
  2411.            DosUnsetExceptionHandler(&xcptregr);
  2412.            return(0L);
  2413.            }
  2414.                /* Get the pointer to the item array        */
  2415.  
  2416.        afl = (PBOOL)PVOIDFROMMP(mp2);
  2417.  
  2418.        if ( plbw->cItems < LONGFROMMP(mp1) )
  2419.            n = plbw->cItems;
  2420.        else
  2421.            n = (LONG)LONGFROMMP(mp1);
  2422.  
  2423.                /* Loop through the list of items and place each */
  2424.                /* one within the list box.  If the list box    */
  2425.                /* contains any items, append the new items to    */
  2426.                /* the end of the list.                */
  2427.  
  2428.        for ( i = 0; i < n; i++ )
  2429.            if ( afl[i] )
  2430.            plbw->plc[0].apli[i]->fl |= LI_CHECKED;
  2431.            else
  2432.            plbw->plc[0].apli[i]->fl &= ~LI_CHECKED;
  2433.  
  2434.        RefreshList(plbw, 0L);
  2435.  
  2436.                /* Remove the exception handle since the lazy    */
  2437.                /* pointer evaluation is done            */
  2438.  
  2439.        DosUnsetExceptionHandler(&xcptregr);
  2440.        return(MRFROMLONG(n));
  2441.        }
  2442.        else
  2443.        return(0L);
  2444.  
  2445.    /*********************************************************************/
  2446.    /*  Extended message:   LMX_QUERYCHECKARRAY                */
  2447.    /*               mp1 = MPFROMLONG(cItems);            */
  2448.    /*               mp2 = MPFROMP(afl);                */
  2449.    /*********************************************************************/
  2450.  
  2451.    case LMX_QUERYCHECKARRAY :
  2452.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2453.        {
  2454.                /* Register exception handler that is used for    */
  2455.                /* the lazy pointer validation tests        */
  2456.  
  2457.        xcptregr.prev_structure   = NULL;
  2458.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2459.  
  2460.        DosSetExceptionHandler(&xcptregr);
  2461.  
  2462.        if ( setjmp(jBuf) )
  2463.            {
  2464.                /* Remove the exception handle since the lazy    */
  2465.                /* pointer evaluation is done            */
  2466.  
  2467.            DosUnsetExceptionHandler(&xcptregr);
  2468.            return(0L);
  2469.            }
  2470.                /* Get the pointer to the item array        */
  2471.  
  2472.        afl = (PBOOL)PVOIDFROMMP(mp2);
  2473.  
  2474.        if ( plbw->cItems < LONGFROMMP(mp1) )
  2475.            n = plbw->cItems;
  2476.        else
  2477.            n = (LONG)LONGFROMMP(mp1);
  2478.  
  2479.                /* Loop through the list of items and place each */
  2480.                /* one within the list box.  If the list box    */
  2481.                /* contains any items, append the new items to    */
  2482.                /* the end of the list.                */
  2483.  
  2484.        for ( i = 0; i < n; i++ )
  2485.            if ( plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2486.            afl[i] = TRUE;
  2487.            else
  2488.            afl[i] = FALSE;
  2489.  
  2490.                /* Remove the exception handle since the lazy    */
  2491.                /* pointer evaluation is done            */
  2492.  
  2493.        DosUnsetExceptionHandler(&xcptregr);
  2494.        return(MRFROMLONG(n));
  2495.        }
  2496.        else
  2497.        return(0L);
  2498.    }
  2499. return(0L);
  2500. }
  2501. #pragma subtitle("   List Manager   - Exception Handler Routine")
  2502. #pragma page( )
  2503.  
  2504. /* --- ListBoxExceptionHandler ------------------------ [ Private ] --- */
  2505. /*                                    */
  2506. /*     This function is used process exceptions under 2.0 and to,    */
  2507. /*     depending on the exception, provide a method of performing    */
  2508. /*     lazy pointer validation for the data types.            */
  2509. /*                                    */
  2510. /*     Upon Entry:                            */
  2511. /*                                    */
  2512. /*     PEXCEPTIONREPORTRECORD        pxcptrepr; = Report Record        */
  2513. /*     PEXCEPTIONREGISTRATIONRECORD pxcptregr; = Registration Record    */
  2514. /*     PCONTEXTRECORD            pcr;       = Context Record     */
  2515. /*     PVOID                sysinfo;   = System Reserved    */
  2516. /*                                    */
  2517. /*     Upon Exit:                            */
  2518. /*                                    */
  2519. /*     ListBoxExceptionHandler = Exception Handling Value        */
  2520. /*                                    */
  2521. /* -------------------------------------------------------------------- */
  2522.  
  2523. APIRET APIENTRY ListBoxExceptionHandler(PEXCEPTIONREPORTRECORD pxcptrepr,
  2524.                     PEXCEPTIONREGISTRATIONRECORD pxcptregr,
  2525.                     PCONTEXTRECORD pcr, PVOID sysinfo)
  2526.  
  2527. {
  2528. #pragma info(nopar)
  2529.  
  2530. if ( EH_EXIT_UNWIND & pxcptrepr->fHandlerFlags )
  2531.    return(XCPT_CONTINUE_SEARCH);
  2532.  
  2533. if ( EH_UNWINDING & pxcptrepr->fHandlerFlags )
  2534.    return(XCPT_CONTINUE_SEARCH);
  2535.  
  2536. if ( EH_NESTED_CALL & pxcptrepr->fHandlerFlags )
  2537.    return(XCPT_CONTINUE_SEARCH);
  2538.  
  2539. if ( pxcptrepr->ExceptionNum == XCPT_ACCESS_VIOLATION )
  2540.    longjmp((INT *)jBuf, 1);
  2541.  
  2542. return(XCPT_CONTINUE_SEARCH);
  2543. }
  2544.