home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lbfix.zip / listmgr.c < prev   
C/C++ Source or Header  |  1994-07-05  |  88KB  |  2,568 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-07-03                        */
  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        */
  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. BOOL        fSelected;           /* Selection    State            */
  959. HHEAPMEM    hHeap;           /* Heap Handle            */
  960. LONG        iVertScroll;       /* Vertical Scroll Position        */
  961. PLISTBOXWIN plbw;           /* List Box Internal    Data Pointer    */
  962. PLISTITEM   pli;           /* List Item    Pointer            */
  963. RECTL        rcl;           /* Display Rectangle            */
  964. UINT        usLen;           /* Length Holder            */
  965. register INT i,    n;           /* Loop Counter            */
  966. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception    Record        */
  967.  
  968. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  969.  
  970. switch ( msg )
  971.    {
  972.    /*********************************************************************/
  973.    /*  Standard    message:   LM_DELETEALL                    */
  974.    /*               mp1 = 0L;                    */
  975.    /*               mp2 = 0L;                    */
  976.    /*********************************************************************/
  977.  
  978.    case    LM_DELETEALL :
  979.                /* Check    to see if any items within the list box    */
  980.                /* which    if there are none, there is nothing to    */
  981.                /* delete and there is no memory    to release    */
  982.  
  983.        if ( plbw->cItems )
  984.        {
  985.                /* Release the heap associated with the list box    */
  986.                /* items    and set    the item count to zero        */
  987.  
  988.        HeapRelease(plbw->plc[0].hHeap);
  989.  
  990.        FocusChange(plbw, plbw->iFocus, FALSE);
  991.        plbw->iFocus    = plbw->iSelected = LIT_NONE;
  992.        plbw->cHorzScroll =
  993.        plbw->cVertScroll =
  994.        plbw->iHorzScroll =
  995.        plbw->iVertScroll = 0L;
  996.        plbw->cItems    = 0UL;
  997.  
  998.                /* Check    to see if the list box is showing and    */
  999.                /* if the case clear the    list area and update    */
  1000.                /* the scroll bars otherwise set    dirty flag to    */
  1001.                /* delay    the scroll bar updating    until it is    */
  1002.                /* visible                    */
  1003.  
  1004.        if (    WinIsWindowShowing(hWnd) )
  1005.            {
  1006.            WinInvalidateRect(hWnd, &plbw->rcl, FALSE);
  1007.            UpdateScrollBars(plbw);
  1008.            }
  1009.        else
  1010.            plbw->fDirty = TRUE;
  1011.        return(MRFROMLONG(TRUE));
  1012.        }
  1013.        break;
  1014.  
  1015.    /*********************************************************************/
  1016.    /*  Standard    message:   LM_DELETEITEM                */
  1017.    /*               mp1 = MPFROMLONG(iItem);            */
  1018.    /*               mp2 = 0L;                    */
  1019.    /*********************************************************************/
  1020.  
  1021.    case    LM_DELETEITEM :
  1022.                /* Check    to see that items within the list box    */
  1023.                /* and that the item requested is within    the    */
  1024.                /* range    of items                */
  1025.  
  1026.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1027.        {
  1028.                /* Reduce the list box item count and check to    */
  1029.                /* see if the last item is being    deleted    in    */
  1030.                /* which    case release the heap for the list box    */
  1031.                /* items                        */
  1032.  
  1033.        if (    --plbw->cItems == 0UL )
  1034.            {
  1035.            HeapRelease(plbw->plc[0].hHeap);
  1036.  
  1037.            FocusChange(plbw, plbw->iFocus, FALSE);
  1038.            plbw->iFocus = plbw->iSelected =    LIT_NONE;
  1039.            plbw->cHorzScroll =
  1040.            plbw->cVertScroll =
  1041.            plbw->iHorzScroll =
  1042.            plbw->iVertScroll = 0L;
  1043.            }
  1044.        else
  1045.            {
  1046.                /* Release the memory allocated for the text of    */
  1047.                /* the item and shift the entires up one        */
  1048.                /* position in place of the entry being        */
  1049.                /* deleted                    */
  1050.  
  1051.            HeapFree(plbw->plc[0].hHeap, plbw->plc[0].apli[LONGFROMMP(mp1)]->pszText);
  1052.            HeapFree(plbw->plc[0].hHeap, plbw->plc[0].apli[LONGFROMMP(mp1)]);
  1053.            if ( LONGFROMMP(mp1) != plbw->cItems )
  1054.            memmove(&plbw->plc[0].apli[LONGFROMMP(mp1)],    &plbw->plc[0].apli[LONGFROMMP(mp1) + 1],
  1055.                (UINT)((plbw->cItems    - LONGFROMMP(mp1)) * sizeof(PLISTITEM)));
  1056.            }
  1057.        if (    (plbw->iVertScroll + plbw->cLinesPage) >= plbw->cItems )
  1058.            {
  1059.            if ( (plbw->iVertScroll = plbw->cItems -    plbw->cLinesPage) < 0 )
  1060.            plbw->iVertScroll = 0;
  1061.            if ( plbw->iFocus > plbw->cLinesPage )
  1062.            plbw->iFocus    = plbw->cLinesPage - 1L;
  1063.            }
  1064.                /* Check    to see if there    are more items within    */
  1065.                /* the list box than can    be displayed which if    */
  1066.                /* the case, perform normal refresh        */
  1067.  
  1068.        if (    plbw->cItems > plbw->cLinesPage    )
  1069.            RefreshList(plbw, (LONG)LONGFROMMP(mp1));
  1070.        else
  1071.                /* Check    to see if the list box is being        */
  1072.                /* displayed                    */
  1073.  
  1074.            if ( WinIsWindowShowing(plbw->hWnd) )
  1075.            {
  1076.                /* List box is visible, need to refresh the    */
  1077.                /* list showing the item    removed.  Form the    */
  1078.                /* rectangle based on the fact that the area    */
  1079.                /* that requires    updating includes the former    */
  1080.                /* last line which is now blank.            */
  1081.  
  1082.            rcl = plbw->rcl;
  1083.            rcl.yTop = plbw->rcl.yTop - ((LONG)LONGFROMMP(mp1) -    plbw->iVertScroll) * plbw->cyItem;
  1084.            if (    plbw->cItems < plbw->cLinesPage    )
  1085.                rcl.yBottom = plbw->rcl.yTop - (plbw->cItems + 1) * plbw->cyItem;
  1086.            WinInvalidateRect(plbw->hWnd, &rcl, FALSE);
  1087.            UpdateScrollBars(plbw);
  1088.            }
  1089.            else
  1090.            plbw->fDirty    = TRUE;
  1091.        }
  1092.        return(MRFROMLONG(plbw->cItems));
  1093.  
  1094.    /*********************************************************************/
  1095.    /*  Standard    message:   LM_INSERTITEM                */
  1096.    /*               mp1 = MPFROMLONG(iItem);            */
  1097.    /*               mp2 = MPFROMP(pszText);            */
  1098.    /*********************************************************************/
  1099.  
  1100.    case    LM_INSERTITEM :
  1101.                /* Determine if items exist within the list box    */
  1102.                /* in which case    may need to resize the array    */
  1103.                /* the for list items otherwise will need to    */
  1104.                /* start    the list off from scratch        */
  1105.  
  1106.        if ( plbw->cItems )
  1107.        {
  1108.                /* Existing list    present, determine if the    */
  1109.                /* modulo boundary encountered in which case    */
  1110.                /* reallocate the list for a set    of new entries.    */
  1111.                /* The list is allocated    in groups of 8,    hence    */
  1112.                /* whenever the list total is a multiple    of 8,    */
  1113.                /* the current list is full and needs to    be    */
  1114.                /* expanded.                    */
  1115.  
  1116.        if (    (plbw->cItems %    CBLK_LIST) == 0    )
  1117.            plbw->plc[0].apli = (PLISTITEM *)HeapRealloc(plbw->plc[0].hHeap,    plbw->plc[0].apli,
  1118.                                 (((plbw->cItems / CBLK_LIST) + 1UL)    * CBLK_LIST) *
  1119.                                 sizeof(PLISTITEM));
  1120.        }
  1121.        else
  1122.        {
  1123.                /* Starting off the list    box from scratch,    */
  1124.                /* create the new heap that is to be used for    */
  1125.                /* list box                    */
  1126.  
  1127.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1128.  
  1129.                /* Allocate the memory needed for the control    */
  1130.                /* information and save the heap    handle within    */
  1131.                /* it                        */
  1132.  
  1133.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1134.        plbw->plc[0].hHeap =    hHeap;
  1135.  
  1136.                /* Allcoate memory for the initial start    of the    */
  1137.                /* list.     The list is allocated in groups of 8,    */
  1138.                /* hence    whenever the list total    is a multiple    */
  1139.                /* of 8,    the current list is full and needs to    */
  1140.                /* be expanded.                    */
  1141.  
  1142.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(hHeap, CBLK_LIST    * sizeof(PLISTITEM));
  1143.        }
  1144.                /* Register exception handler that is used for    */
  1145.                /* the lazy pointer validation tests        */
  1146.  
  1147.        xcptregr.prev_structure     = NULL;
  1148.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1149.  
  1150.        DosSetExceptionHandler(&xcptregr);
  1151.  
  1152.        if ( setjmp(jBuf) )
  1153.        {
  1154.                /* Remove the exception handle since the    lazy    */
  1155.                /* pointer evaluation is    done            */
  1156.  
  1157.        DosUnsetExceptionHandler(&xcptregr);
  1158.        return(MRFROMLONG(TRUE));
  1159.        }
  1160.  
  1161.        plbw->plc[0].apli[plbw->cItems] = (PLISTITEM)HeapMalloc(plbw->plc[0].hHeap, sizeof(LISTITEM));
  1162.  
  1163.                /* Insert the item in the list based on the    */
  1164.                /* method of insertion                */
  1165.  
  1166.        switch (    (LONG)(SHORT)SHORT1FROMMP(mp1) )
  1167.        {
  1168.                /* Method:  Add to end of list box        */
  1169.        case    LIT_END    :
  1170.                /* Set the text of the item being inserted at    */
  1171.                /* the end of the list box list and check to see    */
  1172.                /* if the item is wider than the    rest in    which    */
  1173.                /* case the maximum item    width should be    updated    */
  1174.  
  1175.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[plbw->cItems++],
  1176.                   PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle &    LS_HORZSCROLL) )
  1177.            plbw->cxItem    = plbw->plc[0].apli[plbw->cItems - 1]->cxItem;
  1178.  
  1179.            RefreshList(plbw, plbw->cItems -    1);
  1180.            if ( plbw->fFocus && (plbw->iFocus == LIT_NONE) )
  1181.            SetFocus(plbw, 0L);
  1182.  
  1183.                /* Remove the exception handle since the    lazy    */
  1184.                /* pointer evaluation is    done            */
  1185.  
  1186.            DosUnsetExceptionHandler(&xcptregr);
  1187.            return(MRFROMLONG(plbw->cItems -    1));
  1188.  
  1189.                /* Method:  Add to list box in ascending    order    */
  1190.                /* Method:  Add to list box in descending order    */
  1191.  
  1192.        case    LIT_SORTASCENDING :
  1193.        case    LIT_SORTDESCENDING :
  1194.  
  1195.                /* Set the text of the item being inserted at    */
  1196.                /* the end of the list box list and check to see    */
  1197.                /* if the item is wider than the    rest in    which    */
  1198.                /* case the maximum item    width should be    updated    */
  1199.  
  1200.            if ( (lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[plbw->cItems],
  1201.                   PVOIDFROMMP(mp2)) > plbw->cxItem) && (plbw->flStyle &    LS_HORZSCROLL) )
  1202.            plbw->cxItem    = plbw->plc[0].apli[plbw->cItems]->cxItem;
  1203.  
  1204.            pli = plbw->plc[0].apli[plbw->cItems];
  1205.  
  1206.                /* Determine the    type of    sorting    required    */
  1207.     
  1208.            if ( (LONG)LONGFROMMP(mp1) == LIT_SORTDESCENDING    )
  1209.  
  1210.                /* Sort the list    in descending order        */
  1211.  
  1212.            SortDescending(plbw->plc[0].apli, 0,    plbw->cItems++);
  1213.            else
  1214.                /* Sort the list    in ascending order        */
  1215.  
  1216.            SortAscending(plbw->plc[0].apli, 0, plbw->cItems++);
  1217.  
  1218.            for ( i = 0; i <    plbw->cItems; i++ )
  1219.            if (    plbw->plc[0].apli[i] ==    pli )
  1220.                break;
  1221.            RefreshList(plbw, i);
  1222.            if ( plbw->fFocus && (plbw->iFocus == LIT_NONE) )
  1223.            SetFocus(plbw, 0L);
  1224.            else
  1225.            if (    plbw->iFocus !=    LIT_NONE )
  1226.                for ( n = 0; n <    plbw->cItems; n++ )
  1227.                if (    plbw->plc[0].apli[n]->fl & (LI_FOCUS | LI_SELECTED) )
  1228.                    {
  1229.                    plbw->iSelected = plbw->iFocus =    n;
  1230.                    break;
  1231.                    }
  1232.  
  1233.                /* Remove the exception handle since the    lazy    */
  1234.                /* pointer evaluation is    done            */
  1235.  
  1236.            DosUnsetExceptionHandler(&xcptregr);
  1237.            return(MRFROMLONG(i));
  1238.  
  1239.                /* Method: Add to list box in position indicated    */
  1240.        default :
  1241.                /* Check    to make    sure that the item being    */
  1242.                /* inserted can be inserted in the position    */
  1243.                /* requested                    */
  1244.  
  1245.            if ( (LONGFROMMP(mp1) >=    0L) && (LONGFROMMP(mp1)    <= plbw->cItems) )
  1246.            {
  1247.                /* Check    to make    sure that the item position is    */
  1248.                /* not the next logical entry at    the end    of the    */
  1249.                /* list                        */
  1250.  
  1251.            if (    LONGFROMMP(mp1)    != plbw->cItems    )
  1252.                {
  1253.                /* Inserting the    item somewhere within the list,    */
  1254.                /* therefore open up the    position for the entry    */
  1255.                /* in the correct location shifting the other    */
  1256.                /* entries down a position            */
  1257.  
  1258.                for ( i = plbw->cItems++; i > LONGFROMMP(mp1); i-- )
  1259.                plbw->plc[0].apli[i]    = plbw->plc[0].apli[i -    1];
  1260.                memset(plbw->plc[0].apli[LONGFROMMP(mp1)], 0, sizeof(LISTITEM));
  1261.                }
  1262.            else
  1263.                /* Entry    position essentially the last one, just    */
  1264.                /* bump the entries count since there is    no need    */
  1265.                /* to shuffle things around            */
  1266.  
  1267.                plbw->cItems++;
  1268.  
  1269.                /* Set the text of the item being inserted at    */
  1270.                /* the end of the list box list and check to see    */
  1271.                /* if the item is wider than the    rest in    which    */
  1272.                /* case the maximum item    width should be    updated    */
  1273.  
  1274.            if (    (lSetItemText(plbw->plc[0].hHeap, hWnd,    plbw->plc[0].apli[LONGFROMMP(mp1)],
  1275.                       PVOIDFROMMP(mp2))    > plbw->cxItem)    && (plbw->flStyle & LS_HORZSCROLL) )
  1276.                plbw->cxItem = plbw->plc[0].apli[LONGFROMMP(mp1)]->cxItem;
  1277.  
  1278.            RefreshList(plbw, (LONG)LONGFROMMP(mp1));
  1279.            if (    plbw->fFocus &&    (plbw->iFocus == LIT_NONE) )
  1280.                SetFocus(plbw, 0L);
  1281.  
  1282.                /* Remove the exception handle since the    lazy    */
  1283.                /* pointer evaluation is    done            */
  1284.  
  1285.            DosUnsetExceptionHandler(&xcptregr);
  1286.            return(MRFROMLONG(LONGFROMMP(mp1)));
  1287.            }
  1288.            else
  1289.            {
  1290.                /* Remove the exception handle since the    lazy    */
  1291.                /* pointer evaluation is    done            */
  1292.  
  1293.            DosUnsetExceptionHandler(&xcptregr);
  1294.            return(MRFROMLONG(LIT_ERROR));
  1295.            }
  1296.        }
  1297.  
  1298.    /*********************************************************************/
  1299.    /*  Standard    message:   LM_QUERYITEMCOUNT                */
  1300.    /*               mp1 = 0L;                    */
  1301.    /*               mp2 = 0L;                    */
  1302.    /*********************************************************************/
  1303.  
  1304.    case    LM_QUERYITEMCOUNT :
  1305.        return(MRFROMLONG(plbw->cItems));
  1306.  
  1307.    /*********************************************************************/
  1308.    /*  Standard    message:   LM_QUERYITEMHANDLE                */
  1309.    /*               mp1 = MPFROMLONG(iItem);            */
  1310.    /*               mp2 = 0L;                    */
  1311.    /*********************************************************************/
  1312.  
  1313.    case    LM_QUERYITEMHANDLE :
  1314.                /* Check    to see that items within the list box    */
  1315.                /* and that the item requested is within    the    */
  1316.                /* range    of items                */
  1317.  
  1318.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1319.        return(MRFROMLONG(plbw->plc[0].apli[LONGFROMMP(mp1)]->ulHandle));
  1320.       break;
  1321.  
  1322.    /*********************************************************************/
  1323.    /*  Standard    message:   LM_QUERYITEMTEXT                */
  1324.    /*               mp1 = MPFROM2SHORT(iItem, cch);        */
  1325.    /*               mp2 = MPFROMP(pszText);            */
  1326.    /*********************************************************************/
  1327.  
  1328.    case    LM_QUERYITEMTEXT :
  1329.                /* Check    to see that items within the list box    */
  1330.                /* and that the item requested is within    the    */
  1331.                /* range    of items                */
  1332.  
  1333.        if ( plbw->cItems && ((LONG)SHORT1FROMMP(mp1) < plbw->cItems) &&
  1334.         ((LONG)SHORT2FROMMP(mp1) > 0L) )
  1335.        {
  1336.        memcpy(PVOIDFROMMP(mp2), plbw->plc[0].apli[SHORT1FROMMP(mp1)]->pszText,
  1337.           (plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText + 1) < SHORT2FROMMP(mp1)    ?
  1338.           (plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText + 1) :
  1339.           SHORT2FROMMP(mp1));
  1340.        return(MRFROMLONG(plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText < SHORT2FROMMP(mp1) ?
  1341.                  plbw->plc[0].apli[SHORT1FROMMP(mp1)]->cText :
  1342.                  SHORT2FROMMP(mp1)));
  1343.        }
  1344.        else
  1345.        return(0L);
  1346.  
  1347.    /*********************************************************************/
  1348.    /*  Standard    message:   LM_QUERYITEMTEXTLENGTH            */
  1349.    /*               mp1 = MPFROMLONG(iItem);            */
  1350.    /*               mp2 = 0L;                    */
  1351.    /*********************************************************************/
  1352.  
  1353.    case    LM_QUERYITEMTEXTLENGTH :
  1354.  
  1355.                /* Check    to see that items within the list box    */
  1356.                /* and that the item requested is within    the    */
  1357.                /* range    of items                */
  1358.  
  1359.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1360.        return(MRFROMLONG(plbw->plc[0].apli[LONGFROMMP(mp1)]->cText));
  1361.        break;
  1362.  
  1363.    /*********************************************************************/
  1364.    /*  Standard    message:   LM_QUERYSELECTION                */
  1365.    /*               mp1 = MPFROMLONG(iItemPrev);            */
  1366.    /*               mp2 = 0L;                    */
  1367.    /*********************************************************************/
  1368.  
  1369.    case    LM_QUERYSELECTION :
  1370.        if ( plbw->cItems )
  1371.        if (    plbw->flStyle &    (LS_MULTIPLESEL    | LS_EXTENDEDSEL) )
  1372.            {
  1373.            if ( (LONG)(SHORT)SHORT1FROMMP(mp1) == LIT_FIRST    )
  1374.            {
  1375.            for ( i = 0;    i < plbw->cItems; i++ )
  1376.                if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1377.                return(MRFROMLONG(i));
  1378.  
  1379.            return(MRFROMLONG(LIT_NONE));
  1380.            }
  1381.            else
  1382.            if (    (LONG)(SHORT)SHORT1FROMMP(mp1) >= 0L )
  1383.                {
  1384.                for ( i = (LONG)(SHORT)SHORT1FROMMP(mp1)    + 1; i < plbw->cItems; i++ )
  1385.                if (    plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1386.                    return(MRFROMLONG(i));
  1387.  
  1388.                return(MRFROMLONG(LIT_NONE));
  1389.                }
  1390.            else
  1391.                return(MRFROMLONG(LIT_NONE));
  1392.            }
  1393.        else
  1394.            return(MRFROMLONG(plbw->iSelected));
  1395.        else
  1396.        return(MRFROMLONG(LIT_NONE));
  1397.  
  1398.    /*********************************************************************/
  1399.    /*  Standard    message:   LM_QUERYTOPINDEX                */
  1400.    /*               mp1 = 0L;                    */
  1401.    /*               mp2 = 0L;                    */
  1402.    /*********************************************************************/
  1403.  
  1404.    case    LM_QUERYTOPINDEX :
  1405.        if ( plbw->cItems )
  1406.        return(MRFROMLONG(plbw->iVertScroll));
  1407.        else
  1408.        return(MRFROMLONG(LIT_NONE));
  1409.  
  1410.    /*********************************************************************/
  1411.    /*  Standard    message:   LM_SEARCHSTRING                */
  1412.    /*               mp1 = MPFROM2SHORT(usCmd, iItem);        */
  1413.    /*               mp2 = MPFROMP(pszSearch);            */
  1414.    /*********************************************************************/
  1415.  
  1416.    case    LM_SEARCHSTRING    :
  1417.  
  1418.                /* Check    to see that items within the list box    */
  1419.                /* and that the item requested is within    the    */
  1420.                /* range    of items                */
  1421.  
  1422.        if ( plbw->cItems && ((LONG)(SHORT)SHORT2FROMMP(mp1) < plbw->cItems) )
  1423.        {
  1424.                /* Check    to make    sure that valid    values have    */
  1425.                /* been provided                    */
  1426.  
  1427.        if (    (((ULONG)SHORT1FROMMP(mp1) & (LSS_PREFIX | LSS_SUBSTRING)) == (LSS_PREFIX | LSS_SUBSTRING)) ||
  1428.         ((PSZ)PVOIDFROMMP(mp2) == NULL)    )
  1429.            return(MRFROMLONG(LIT_ERROR));
  1430.  
  1431.                /* Set the starting index point            */
  1432.  
  1433.        if (    (LONG)(SHORT)SHORT2FROMMP(mp1) == LIT_FIRST )
  1434.            n = 0;
  1435.        else
  1436.            n = (LONG)(SHORT)SHORT2FROMMP(mp1) + 1;
  1437.  
  1438.                /* Check    to see if the search is    for the    prefix    */
  1439.                /* portion of the list box item            */
  1440.  
  1441.        if (    (ULONG)SHORT1FROMMP(mp1) & LSS_PREFIX )
  1442.            {
  1443.            usLen = strlen((PSZ)PVOIDFROMMP(mp2));
  1444.  
  1445.            if ( (ULONG)SHORT1FROMMP(mp1) & LSS_CASESENSITIVE )
  1446.            {
  1447.            for ( i = n;    i < plbw->cItems; i++ )
  1448.                if ( strncmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1449.                return(MRFROMLONG(i));
  1450.  
  1451.            for ( i = 0;    i < n; i++ )
  1452.                if ( strncmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1453.                return(MRFROMLONG(i));
  1454.            }
  1455.            else
  1456.            {
  1457.            for ( i = n;    i < plbw->cItems; i++ )
  1458.                if ( strnicmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1459.                return(MRFROMLONG(i));
  1460.  
  1461.            for ( i = 0;    i < n; i++ )
  1462.                if ( strnicmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2), usLen) == 0 )
  1463.                return(MRFROMLONG(i));
  1464.            }
  1465.            return(MRFROMLONG(LIT_NONE));
  1466.            }
  1467.        else
  1468.                /* Check    to see if the search is    for a substring    */
  1469.                /* within the list box items            */
  1470.  
  1471.            if ( (ULONG)SHORT1FROMMP(mp1) & LSS_SUBSTRING )
  1472.            {
  1473.            for ( i = n;    i < plbw->cItems; i++ )
  1474.                if ( strstr(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) )
  1475.                return(MRFROMLONG(i));
  1476.  
  1477.            for ( i = 0;    i < n; i++ )
  1478.                if ( strstr(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) )
  1479.                return(MRFROMLONG(i));
  1480.  
  1481.            return(MRFROMLONG(LIT_NONE));
  1482.            }
  1483.            else
  1484.                /* Check    to see if the search is    case senstive    */
  1485.  
  1486.            if (    (ULONG)SHORT1FROMMP(mp1) & LSS_CASESENSITIVE )
  1487.                {
  1488.                for ( i = n; i <    plbw->cItems; i++ )
  1489.                if (    strcmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) ==    0 )
  1490.                    return(MRFROMLONG(i));
  1491.  
  1492.                for ( i = 0; i <    n; i++ )
  1493.                if (    strcmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) ==    0 )
  1494.                    return(MRFROMLONG(i));
  1495.  
  1496.                return(MRFROMLONG(LIT_NONE));
  1497.                }
  1498.            else
  1499.                /* Search is case insensitive            */
  1500.                {
  1501.                for ( i = n; i <    plbw->cItems; i++ )
  1502.                if (    stricmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1503.                    return(MRFROMLONG(i));
  1504.  
  1505.                for ( i = 0; i <    n; i++ )
  1506.                if (    stricmp(plbw->plc[0].apli[i]->pszText, (PSZ)PVOIDFROMMP(mp2)) == 0 )
  1507.                    return(MRFROMLONG(i));
  1508.  
  1509.                return(MRFROMLONG(LIT_NONE));
  1510.                }
  1511.        }
  1512.        else
  1513.        return(MRFROMLONG(LIT_ERROR));
  1514.  
  1515.    /*********************************************************************/
  1516.    /*  Standard    message:   LM_SELECTITEM                */
  1517.    /*               mp1 = MPFROMLONG(iItem);            */
  1518.    /*               mp2 = MPFROMLONG(fSelect);            */
  1519.    /*********************************************************************/
  1520.  
  1521.    case    LM_SELECTITEM :
  1522.        if ( (LONG)LONGFROMMP(mp1) == LIT_NONE )
  1523.        {
  1524.        for ( i = 0;    i < plbw->cItems; i++ )
  1525.            if (plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1526.            {
  1527.            SaveSelectState(0L, i);
  1528.            plbw->plc[0].apli[i]->fl &= ~LI_SELECTED;
  1529.  
  1530.                /* Invert the rectangle of the entry to return    */
  1531.                /* it back to its normal    display    colour        */
  1532.  
  1533.            DrawSelection(plbw, i);
  1534.            }
  1535.        return(MRFROMLONG(TRUE));
  1536.        }
  1537.        else
  1538.                /* Check    to see that items within the list box    */
  1539.                /* and that the item requested is within    the    */
  1540.                /* range    of items                */
  1541.  
  1542.        if (    LONGFROMMP(mp1)    < plbw->cItems )
  1543.            {
  1544.            if ( plbw->plc[0].apli[LONGFROMMP(mp1)]->fl & LI_SELECTED )
  1545.            fSelected = TRUE;
  1546.            else
  1547.            fSelected = FALSE;
  1548.  
  1549.                /* Check    to see if the list box allows for    */
  1550.                /* multiple selections                */
  1551.  
  1552.            if ( plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL) )
  1553.            {
  1554.                /* Multiple selections allowed, select or    */
  1555.                /* deselected the requested item            */
  1556.  
  1557.            SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1558.            if (    (BOOL)LONGFROMMP(mp2) )
  1559.                {
  1560.                RemoveFocus(plbw);
  1561.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl |= (LI_SELECTED |    LI_FOCUS);
  1562.                FocusChange(plbw, plbw->iFocus =    (LONG)LONGFROMMP(mp1), TRUE);
  1563.                if ( plbw->iSelected == -1 )
  1564.                plbw->iAnchor = plbw->iSelected = plbw->iFocus;
  1565.                }
  1566.            else
  1567.                {
  1568.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~LI_SELECTED;
  1569.                for ( i = (LONG)LONGFROMMP(mp1),    plbw->iSelected    = -1; i    >= 0; i-- )
  1570.                if (    plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1571.                    {
  1572.                    plbw->iSelected = i;
  1573.                    break;
  1574.                    }
  1575.  
  1576.                if ( plbw->iSelected == -1 )
  1577.                for ( i = (LONG)LONGFROMMP(mp1); i <    plbw->cItems; i++ )
  1578.                    if ( plbw->plc[0].apli[i]->fl & LI_SELECTED )
  1579.                    {
  1580.                    plbw->iSelected = i;
  1581.                    break;
  1582.                    }
  1583.                }
  1584.                /* Invert the rectangle of the entry to return    */
  1585.                /* it back to its normal    display    colour        */
  1586.  
  1587.            DrawSelection(plbw, (LONG)LONGFROMMP(mp1));
  1588.            }
  1589.            else
  1590.            {
  1591.                /* Single selection only    allowed    for the    list    */
  1592.                /* box, deselect    the previous item and then    */
  1593.                /* select the desired one            */
  1594.  
  1595.            if (    (BOOL)LONGFROMMP(mp2) )
  1596.                {
  1597.                if ( plbw->iSelected != LIT_NONE    )
  1598.                {
  1599.                SaveSelectState(0L, plbw->iSelected);
  1600.                plbw->plc[0].apli[plbw->iSelected]->fl &= ~(LI_SELECTED | LI_FOCUS);
  1601.  
  1602.                /* Invert the rectangle of the entry to return    */
  1603.                /* it back to its normal    display    colour        */
  1604.  
  1605.                DrawSelection(plbw, plbw->iSelected);
  1606.                }
  1607.                SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1608.                plbw->plc[0].apli[plbw->iFocus =    plbw->iSelected    = (LONG)LONGFROMMP(mp1)]->fl |=    (LI_SELECTED | LI_FOCUS);
  1609.                }
  1610.            else
  1611.                {
  1612.                SaveSelectState(0L, (LONG)LONGFROMMP(mp1));
  1613.                plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~(LI_SELECTED | LI_FOCUS);
  1614.                plbw->iSelected = plbw->iFocus =    LIT_NONE;
  1615.                }
  1616.                /* Determine if the selected item should    be    */
  1617.                /* centred within the list making sure that    */
  1618.                /* this only occurs when    item is    not in the last    */
  1619.                /* page of the list box or when the list    box is    */
  1620.                /* less than a full page                */
  1621.  
  1622.            if (    plbw->iFocus !=    LIT_NONE )
  1623.                {
  1624.                if ( plbw->cItems < plbw->cLinesPage )
  1625.                iVertScroll = plbw->iVertScroll;
  1626.                else
  1627.                if (    (iVertScroll = plbw->iFocus - plbw->cLinesPage / 2L) < 0L )
  1628.                    iVertScroll = 0L;
  1629.                else
  1630.                    if ( iVertScroll    > (plbw->cItems    - plbw->cLinesPage) )
  1631.                    iVertScroll = plbw->cItems -    plbw->cLinesPage;
  1632.  
  1633.                if ( plbw->iVertScroll != iVertScroll )
  1634.                {
  1635.                RefreshList(plbw, plbw->iVertScroll = iVertScroll);
  1636.                mrNotifyOwner(plbw, LN_SCROLL);
  1637.                }
  1638.                else
  1639.                if (    plbw->iSelected    != LIT_NONE )
  1640.                    DrawSelection(plbw, plbw->iSelected);
  1641.                }
  1642.            else
  1643.                DrawSelection(plbw, (LONG)LONGFROMMP(mp1));
  1644.  
  1645.            if (    LONGFROMMP(mp1)    )
  1646.                FocusChange(plbw, (LONG)LONGFROMMP(mp1),    TRUE);
  1647.            }
  1648.  
  1649.            if ( fSelected != (BOOL)LONGFROMMP(mp2) )
  1650.            mrNotifyOwner(plbw, LN_SELECT);
  1651.            return(MRFROMLONG(TRUE));
  1652.            }
  1653.        else
  1654.            return(MRFROMLONG(FALSE));
  1655.  
  1656.    /*********************************************************************/
  1657.    /*  Standard    message:   LM_SETITEMHANDLE                */
  1658.    /*               mp1 = MPFROMLONG(iItem);            */
  1659.    /*               mp2 = MPFROMLONG(ulHandle);            */
  1660.    /*********************************************************************/
  1661.  
  1662.    case    LM_SETITEMHANDLE :
  1663.  
  1664.                /* Check    to see that items within the list box    */
  1665.                /* and that the item requested is within    the    */
  1666.                /* range    of items                */
  1667.  
  1668.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) )
  1669.        {
  1670.        plbw->plc[0].apli[LONGFROMMP(mp1)]->ulHandle    = (ULONG)LONGFROMMP(mp2);
  1671.        return(MRFROMLONG(TRUE));
  1672.        }
  1673.        break;
  1674.  
  1675.    /*********************************************************************/
  1676.    /*  Standard    message:   LM_SETITEMHEIGHT                */
  1677.    /*               mp1 = MPFROMLONG(lHeight);            */
  1678.    /*               mp2 = 0L                    */
  1679.    /*********************************************************************/
  1680.  
  1681.    case    LM_SETITEMHEIGHT :
  1682.        if ( LONGFROMMP(mp1) > 0L )
  1683.        {
  1684.        plbw->cyItem    = (LONG)LONGFROMMP(mp1);
  1685.        SizeListBox(plbw);
  1686.        return(MRFROMLONG(TRUE));
  1687.        }
  1688.        break;
  1689.  
  1690.    /*********************************************************************/
  1691.    /*  Standard    message:   LM_SETITEMTEXT                */
  1692.    /*               mp1 = MPFROMLONG(iItem);            */
  1693.    /*               mp2 = MPFROMP(pszText);            */
  1694.    /*********************************************************************/
  1695.  
  1696.    case    LM_SETITEMTEXT :
  1697.                /* Check    to see that items within the list box    */
  1698.                /* and that the item requested is within    the    */
  1699.                /* range    of items                */
  1700.  
  1701.        if ( plbw->cItems && (LONGFROMMP(mp1) < plbw->cItems) &&    PVOIDFROMMP(mp2) )
  1702.        {
  1703.                /* Register exception handler that is used for    */
  1704.                /* the lazy pointer validation tests        */
  1705.  
  1706.        xcptregr.prev_structure   = NULL;
  1707.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1708.  
  1709.        DosSetExceptionHandler(&xcptregr);
  1710.  
  1711.        if (    setjmp(jBuf) )
  1712.            {
  1713.                /* Remove the exception handle since the    lazy    */
  1714.                /* pointer evaluation is    done            */
  1715.  
  1716.            DosUnsetExceptionHandler(&xcptregr);
  1717.            return(MRFROMLONG(TRUE));
  1718.            }
  1719.        HeapFree(plbw->plc[0].hHeap,    plbw->plc[0].apli[LONGFROMMP(mp1)]->pszText);
  1720.        if (    (lSetItemText(plbw->plc[0].hHeap, hWnd,    plbw->plc[0].apli[LONGFROMMP(mp1)],
  1721.                   PVOIDFROMMP(mp2))    > plbw->cxItem)    && (plbw->flStyle & LS_OWNERDRAW) )
  1722.            plbw->cxItem = plbw->plc[0].apli[LONGFROMMP(mp1)]->cxItem;
  1723.  
  1724.                /* Remove the exception handle since the    lazy    */
  1725.                /* pointer evaluation is    done            */
  1726.  
  1727.        DosUnsetExceptionHandler(&xcptregr);
  1728.        return(MRFROMLONG(TRUE));
  1729.        }
  1730.        break;
  1731.  
  1732.    /*********************************************************************/
  1733.    /*  Standard    message:   LM_SETTOPINDEX                */
  1734.    /*               mp1 = MPFROMLONG(item);            */
  1735.    /*               mp2 = 0L                    */
  1736.    /*********************************************************************/
  1737.  
  1738.    case    LM_SETTOPINDEX :
  1739.                /* Check    to see that items within the list box    */
  1740.                /* and that the item requested is within    the    */
  1741.                /* range    of items                */
  1742.  
  1743.        if ( plbw->cItems && (LONGFROMMP(mp1) > 0) )
  1744.        {
  1745.        if (    LONGFROMMP(mp1)    < plbw->cItems    )
  1746.            if ( plbw->cItems > plbw->cLinesPage )
  1747.            if (    LONGFROMMP(mp1)    > (plbw->cItems    - plbw->cLinesPage) )
  1748.                plbw->iVertScroll = plbw->cItems    - plbw->cLinesPage;
  1749.            else
  1750.                if ( plbw->cItems <= plbw->cLinesPage )
  1751.                plbw->iVertScroll = 0L;
  1752.                else
  1753.                plbw->iVertScroll = (LONG)LONGFROMMP(mp1);
  1754.            else
  1755.            plbw->iVertScroll = 0L;
  1756.        else
  1757.            plbw->iVertScroll = 0L;
  1758.  
  1759.        return(MRFROMLONG(TRUE));
  1760.        }
  1761.  
  1762.        break;
  1763.    }
  1764. return(0L);
  1765. }
  1766. #pragma    subtitle("   List Manager - Extended List Box Messages Procedure")
  1767. #pragma    page( )
  1768.  
  1769. /* --- mrExtendedListHandler --------------------------- [ Public ] ---    */
  1770. /*                                    */
  1771. /*     This function is    used to    process    the extended messages for the    */
  1772. /*     list box    control    window.                        */
  1773. /*                                    */
  1774. /*     Upon Entry:                            */
  1775. /*                                    */
  1776. /*     HWND   hWnd; = Window Handle                    */
  1777. /*     ULONG  msg;  = PM Message                    */
  1778. /*     MPARAM mp1;  = Message Parameter    1                */
  1779. /*     MPARAM mp2;  = Message Parameter    2                */
  1780. /*                                    */
  1781. /*     Upon Exit:                            */
  1782. /*                                    */
  1783. /*     mrExtendedListHandler = Message Handling    Result            */
  1784. /*                                    */
  1785. /* --------------------------------------------------------------------    */
  1786.  
  1787. MRESULT    EXPENTRY mrExtendedListHandler(HWND hWnd, ULONG    msg, MPARAM mp1, MPARAM    mp2)
  1788.  
  1789. {
  1790. HHEAPMEM     hHeap;           /* Heap Handle            */
  1791. PLISTITEM    albi;           /* List Box Item Input Pointer    */
  1792. PLISTBOXWIN  plbw;           /* List Box Internal    Data Pointer    */
  1793. PSZ         *apsz;           /* String Array Pointer        */
  1794. PULONG         aul;           /* Handle Array Pointer        */
  1795. register INT i,    n;           /* Loop Counter            */
  1796. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception    Record        */
  1797.  
  1798. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1799.  
  1800. switch ( msg )
  1801.    {
  1802.  
  1803.    /*********************************************************************/
  1804.    /*  Extended    message:   LMX_ADDARRAY                    */
  1805.    /*               mp1 = MPFROMLONG(cItems);            */
  1806.    /*               mp2 = MPFROMP(apsz);                */
  1807.    /*********************************************************************/
  1808.  
  1809.    case    LMX_ADDARRAY :
  1810.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  1811.        {
  1812.                /* Check    to see if any items within the list box    */
  1813.                /* which    if there are none, there is nothing to    */
  1814.                /* delete and there is no memory    to release    */
  1815.  
  1816.        if (    plbw->cItems ==    0 )
  1817.            {
  1818.                /* Starting off the list    box from scratch,    */
  1819.                /* create the new heap that is to be used for    */
  1820.                /* list box                    */
  1821.  
  1822.            hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1823.  
  1824.                /* Allocate the memory needed for the control    */
  1825.                /* information and save the heap    handle within    */
  1826.                /* it                        */
  1827.  
  1828.            plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1829.  
  1830.                /* Allocate memory for the initial start    of the    */
  1831.                /* list.     The list is allocated in groups of 8,    */
  1832.                /* hence    whenever the list total    is a multiple    */
  1833.                /* of 8,    the current list is full and needs to    */
  1834.                /* be expanded.                    */
  1835.  
  1836.            plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap =    hHeap,
  1837.                                (((LONGFROMMP(mp1) /    CBLK_LIST) + 1UL) * CBLK_LIST) *
  1838.                                sizeof(PLISTITEM *));
  1839.            }
  1840.        else
  1841.            plbw->plc[0].apli = (PLISTITEM *)HeapRealloc(plbw->plc[0].hHeap,    plbw->plc[0].apli,
  1842.                                 ((((LONGFROMMP(mp1)    + plbw->cItems)    / CBLK_LIST) + 1UL) * CBLK_LIST) *
  1843.                                 sizeof(PLISTITEM *));
  1844.  
  1845.                /* Register exception handler that is used for    */
  1846.                /* the lazy pointer validation tests        */
  1847.  
  1848.        xcptregr.prev_structure   = NULL;
  1849.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  1850.  
  1851.        DosSetExceptionHandler(&xcptregr);
  1852.  
  1853.        if (    setjmp(jBuf) )
  1854.            {
  1855.            HeapRelease(hHeap);
  1856.  
  1857.                /* Remove the exception handle since the    lazy    */
  1858.                /* pointer evaluation is    done            */
  1859.  
  1860.            DosUnsetExceptionHandler(&xcptregr);
  1861.            return(MRFROMLONG(TRUE));
  1862.            }
  1863.                /* Get the pointer to the item array        */
  1864.  
  1865.        apsz    = (PSZ *)PVOIDFROMMP(mp2);
  1866.  
  1867.                /* Loop through the list    of items and place each    */
  1868.                /* one within the list box.  If the list    box    */
  1869.                /* contains any items, append the new items to    */
  1870.                /* the end of the list.                */
  1871.  
  1872.        for ( i = 0,    n = plbw->cItems; i < LONGFROMMP(mp1); i++, n++    )
  1873.            {
  1874.            plbw->plc[0].apli[n] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  1875.            if ( apsz[i] == NULL )
  1876.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[n],    "") ;
  1877.            else
  1878.            if (    (lSetItemText(plbw->plc[0].hHeap, hWnd,    plbw->plc[0].apli[n],
  1879.                       apsz[i]) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  1880.                plbw->cxItem = plbw->plc[0].apli[n]->cxItem;
  1881.            }
  1882.                /* Save the list    box length and refresh the    */
  1883.                /* list box                    */
  1884.  
  1885.        plbw->cItems    += (LONG)LONGFROMMP(mp1);
  1886.        RefreshList(plbw, 0L);
  1887.  
  1888.                /* Remove the exception handle since the    lazy    */
  1889.                /* pointer evaluation is    done            */
  1890.  
  1891.        DosUnsetExceptionHandler(&xcptregr);
  1892.        }
  1893.        else
  1894.        return(MRFROMLONG(TRUE));
  1895.        break;
  1896.  
  1897.    /*********************************************************************/
  1898.    /*  Extended    message:   LMX_CALCSIZE                    */
  1899.    /*               mp1 = MPFROMLONG(cLines);            */
  1900.    /*               mp2 = 0L;                    */
  1901.    /*********************************************************************/
  1902.  
  1903.    case    LMX_CALCSIZE :
  1904.        if ( LONGFROMMP(mp1) > 0L )
  1905.        if (    plbw->flStyle &    LS_NOADJUSTPOS )
  1906.            return(MRFROMLONG(MAKELONG(plbw->cx, plbw->cy)));
  1907.        else
  1908.            return(MRFROMLONG(MAKELONG(plbw->cx,
  1909.                       LONGFROMMP(mp1) * plbw->cyItem + 2L +
  1910.                       (plbw->flStyle & LS_HORZSCROLL ? plbw->cyScroll : 2L))));
  1911.        break;
  1912.  
  1913.    /*********************************************************************/
  1914.    /*  Extended    message:   LMX_CALCLINECOUNT                */
  1915.    /*               mp1 = MPFROMLONG(lHeight);            */
  1916.    /*               mp2 = 0L;                    */
  1917.    /*********************************************************************/
  1918.  
  1919.    case    LMX_CALCLINECOUNT :
  1920.        if ( LONGFROMMP(mp1) > 0L )
  1921.        return(MRFROMLONG((LONGFROMMP(mp1) -    (2L +
  1922.                   (plbw->flStyle & LS_HORZSCROLL ? plbw->cyScroll :    2L))) /
  1923.                   plbw->cyItem));
  1924.        break;
  1925.  
  1926.    /*********************************************************************/
  1927.    /*  Extended    message:   LMX_SETITEMCOUNT                */
  1928.    /*               mp1 = MPFROMLONG(cItems);            */
  1929.    /*               mp2 = 0L;                    */
  1930.    /*********************************************************************/
  1931.  
  1932.    case    LMX_SETITEMCOUNT :
  1933.        if ( LONGFROMMP(mp1) > 0L )
  1934.        {
  1935.                /* Check    to see if any items within the list box    */
  1936.                /* which    if there are none, there is nothing to    */
  1937.                /* delete and there is no memory    to release    */
  1938.  
  1939.        if (    plbw->cItems )
  1940.            {
  1941.                /* Release the heap associated with the list box    */
  1942.                /* items    and set    the item count to zero        */
  1943.  
  1944.            HeapRelease(plbw->plc[0].hHeap);
  1945.  
  1946.            plbw->cHorzScroll =
  1947.            plbw->cVertScroll =
  1948.            plbw->iHorzScroll =
  1949.            plbw->iVertScroll = 0L;
  1950.            plbw->cItems = 0UL;
  1951.            plbw->iFocus = plbw->iSelected =    LIT_NONE;
  1952.            }
  1953.                /* Starting off the list    box from scratch,    */
  1954.                /* create the new heap that is to be used for    */
  1955.                /* list box                    */
  1956.  
  1957.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  1958.  
  1959.                /* Allocate the memory needed for the control    */
  1960.                /* information and save the heap    handle within    */
  1961.                /* it                        */
  1962.  
  1963.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  1964.  
  1965.                /* Allocate memory for the initial start    of the    */
  1966.                /* list.     The list is allocated in groups of 8,    */
  1967.                /* hence    whenever the list total    is a multiple    */
  1968.                /* of 8,    the current list is full and needs to    */
  1969.                /* be expanded.                    */
  1970.  
  1971.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  1972.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) *    CBLK_LIST) *
  1973.                                sizeof(PLISTITEM));
  1974.  
  1975.        for ( i = 0;    i < (INT)LONGFROMMP(mp1); i++ )
  1976.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  1977.  
  1978.        plbw->cItems    = (LONG)LONGFROMMP(mp1);
  1979.        RefreshList(plbw, 0L);
  1980.        }
  1981.        else
  1982.        return(MRFROMLONG(TRUE));
  1983.        break;
  1984.  
  1985.    /*********************************************************************/
  1986.    /*  Extended    message:   LMX_SETARRAY                    */
  1987.    /*               mp1 = MPFROMLONG(cItems);            */
  1988.    /*               mp2 = MPFROMP(apsz);                */
  1989.    /*********************************************************************/
  1990.  
  1991.    case    LMX_SETARRAY :
  1992.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  1993.        {
  1994.                /* Check    to see if any items within the list box    */
  1995.                /* which    if there are none, there is nothing to    */
  1996.                /* delete and there is no memory    to release    */
  1997.  
  1998.        if (    plbw->cItems )
  1999.            {
  2000.                /* Release the heap associated with the list box    */
  2001.                /* items    and set    the item count to zero        */
  2002.  
  2003.            HeapRelease(plbw->plc[0].hHeap);
  2004.  
  2005.            FocusChange(plbw, plbw->iFocus, FALSE);
  2006.            plbw->iFocus = plbw->iSelected =    LIT_NONE;
  2007.            plbw->cHorzScroll =
  2008.            plbw->cVertScroll =
  2009.            plbw->iHorzScroll =
  2010.            plbw->iVertScroll = 0L;
  2011.            plbw->cItems = 0UL;
  2012.            }
  2013.                /* Register exception handler that is used for    */
  2014.                /* the lazy pointer validation tests        */
  2015.  
  2016.        xcptregr.prev_structure   = NULL;
  2017.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2018.  
  2019.        DosSetExceptionHandler(&xcptregr);
  2020.  
  2021.        if (    setjmp(jBuf) )
  2022.            {
  2023.            HeapRelease(hHeap);
  2024.  
  2025.                /* Remove the exception handle since the    lazy    */
  2026.                /* pointer evaluation is    done            */
  2027.  
  2028.            DosUnsetExceptionHandler(&xcptregr);
  2029.            return(MRFROMLONG(TRUE));
  2030.            }
  2031.                /* Starting off the list    box from scratch,    */
  2032.                /* create the new heap that is to be used for    */
  2033.                /* list box                    */
  2034.  
  2035.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  2036.  
  2037.                /* Allocate the memory needed for the control    */
  2038.                /* information and save the heap    handle within    */
  2039.                /* it                        */
  2040.  
  2041.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  2042.  
  2043.                /* Allocate memory for the initial start    of the    */
  2044.                /* list.     The list is allocated in groups of 8,    */
  2045.                /* hence    whenever the list total    is a multiple    */
  2046.                /* of 8,    the current list is full and needs to    */
  2047.                /* be expanded.                    */
  2048.  
  2049.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  2050.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) *    CBLK_LIST) *
  2051.                                sizeof(PLISTITEM    *));
  2052.  
  2053.                /* Get the pointer to the item array        */
  2054.  
  2055.        apsz    = (PSZ *)PVOIDFROMMP(mp2);
  2056.  
  2057.                /* Loop through the list    of items and place each    */
  2058.                /* one within the list box.  If the list    box    */
  2059.                /* contains any items, append the new items to    */
  2060.                /* the end of the list.                */
  2061.  
  2062.        for ( i = 0;    i < LONGFROMMP(mp1); i++ )
  2063.            {
  2064.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  2065.            if ( apsz[i] == NULL )
  2066.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i],    "") ;
  2067.            else
  2068.            if (    (lSetItemText(plbw->plc[0].hHeap, hWnd,    plbw->plc[0].apli[i],
  2069.                       apsz[i]) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  2070.                plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  2071.            }
  2072.                /* Save the list    box length and refresh the    */
  2073.                /* list box                    */
  2074.  
  2075.        plbw->cItems    += (LONG)LONGFROMMP(mp1);
  2076.        RefreshList(plbw, 0L);
  2077.  
  2078.                /* Remove the exception handle since the    lazy    */
  2079.                /* pointer evaluation is    done            */
  2080.  
  2081.        DosUnsetExceptionHandler(&xcptregr);
  2082.        }
  2083.        else
  2084.        return(MRFROMLONG(TRUE));
  2085.        break;
  2086.  
  2087.    /*********************************************************************/
  2088.    /*  Extended    message:   LMX_SETARRAY                    */
  2089.    /*               mp1 = MPFROMLONG(cItems);            */
  2090.    /*               mp2 = MPFROMP(aul);                */
  2091.    /*********************************************************************/
  2092.  
  2093.    case    LMX_SETARRAYHANDLES :
  2094.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2095.        {
  2096.        if (    LONGFROMMP(mp1)    > plbw->cItems )
  2097.            return(MRFROMLONG(TRUE));
  2098.  
  2099.                /* Register exception handler that is used for    */
  2100.                /* the lazy pointer validation tests        */
  2101.  
  2102.        xcptregr.prev_structure   = NULL;
  2103.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2104.  
  2105.        DosSetExceptionHandler(&xcptregr);
  2106.  
  2107.        if (    setjmp(jBuf) )
  2108.            {
  2109.                /* Remove the exception handle since the    lazy    */
  2110.                /* pointer evaluation is    done            */
  2111.  
  2112.            DosUnsetExceptionHandler(&xcptregr);
  2113.            return(MRFROMLONG(TRUE));
  2114.            }
  2115.                /* Get the pointer to the item array        */
  2116.  
  2117.        aul = (PULONG)PVOIDFROMMP(mp2);
  2118.  
  2119.                /* Loop through the list    of items and place each    */
  2120.                /* one within the list box.  If the list    box    */
  2121.                /* contains any items, append the new items to    */
  2122.                /* the end of the list.                */
  2123.  
  2124.        for ( i = 0;    i < LONGFROMMP(mp1); i++ )
  2125.            plbw->plc[0].apli[i]->ulHandle =    aul[i];
  2126.  
  2127.                /* Remove the exception handle since the    lazy    */
  2128.                /* pointer evaluation is    done            */
  2129.  
  2130.        DosUnsetExceptionHandler(&xcptregr);
  2131.        }
  2132.        else
  2133.        return(MRFROMLONG(TRUE));
  2134.        break;
  2135.  
  2136.    /*********************************************************************/
  2137.    /*  Extended    message:   LMX_SETARRAYITEMS                */
  2138.    /*               mp1 = MPFROMLONG(cItems);            */
  2139.    /*               mp2 = MPFROMP(lbi);                */
  2140.    /*********************************************************************/
  2141.  
  2142.    case    LMX_SETARRAYITEMS :
  2143.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2144.        {
  2145.                /* Check    to see if any items within the list box    */
  2146.                /* which    if there are none, there is nothing to    */
  2147.                /* delete and there is no memory    to release    */
  2148.  
  2149.        if (    plbw->cItems )
  2150.            {
  2151.                /* Release the heap associated with the list box    */
  2152.                /* items    and set    the item count to zero        */
  2153.  
  2154.            HeapRelease(plbw->plc[0].hHeap);
  2155.  
  2156.            FocusChange(plbw, plbw->iFocus, FALSE);
  2157.            plbw->iFocus = plbw->iSelected =    LIT_NONE;
  2158.            plbw->cHorzScroll =
  2159.            plbw->cVertScroll =
  2160.            plbw->iHorzScroll =
  2161.            plbw->iVertScroll = 0L;
  2162.            plbw->cItems = 0UL;
  2163.            }
  2164.                /* Register exception handler that is used for    */
  2165.                /* the lazy pointer validation tests        */
  2166.  
  2167.        xcptregr.prev_structure   = NULL;
  2168.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2169.  
  2170.        DosSetExceptionHandler(&xcptregr);
  2171.  
  2172.        if (    setjmp(jBuf) )
  2173.            {
  2174.            HeapRelease(hHeap);
  2175.  
  2176.                /* Remove the exception handle since the    lazy    */
  2177.                /* pointer evaluation is    done            */
  2178.  
  2179.            DosUnsetExceptionHandler(&xcptregr);
  2180.            return(MRFROMLONG(TRUE));
  2181.            }
  2182.                /* Starting off the list    box from scratch,    */
  2183.                /* create the new heap that is to be used for    */
  2184.                /* list box                    */
  2185.  
  2186.        hHeap = HeapAlloc(HALLOC_DEFAULT, HALLOC_DEFAULT);
  2187.  
  2188.                /* Allocate the memory needed for the control    */
  2189.                /* information and save the heap    handle within    */
  2190.                /* it                        */
  2191.  
  2192.        plbw->plc = (PLISTCOL)HeapMalloc(hHeap, sizeof(LISTCOL));
  2193.  
  2194.                /* Allocate memory for the initial start    of the    */
  2195.                /* list.     The list is allocated in groups of 8,    */
  2196.                /* hence    whenever the list total    is a multiple    */
  2197.                /* of 8,    the current list is full and needs to    */
  2198.                /* be expanded.                    */
  2199.  
  2200.        plbw->plc[0].apli = (PLISTITEM *)HeapMalloc(plbw->plc[0].hHeap = hHeap,
  2201.                                (((LONGFROMMP(mp1) / CBLK_LIST) + 1UL) *    CBLK_LIST) *
  2202.                                sizeof(PLISTITEM    *));
  2203.  
  2204.                /* Get the pointer to the item array        */
  2205.  
  2206.        albi    = (PLISTITEM)PVOIDFROMMP(mp2);
  2207.  
  2208.                /* Loop through the list    of items and place each    */
  2209.                /* one within the list box.  If the list    box    */
  2210.                /* contains any items, append the new items to    */
  2211.                /* the end of the list.                */
  2212.  
  2213.        for ( i = 0;    i < LONGFROMMP(mp1); i++ )
  2214.            {
  2215.            plbw->plc[0].apli[i] = (PLISTITEM)HeapMalloc(hHeap, sizeof(LISTITEM));
  2216.  
  2217.            if ( albi[i].pszText == NULL )
  2218.            lSetItemText(plbw->plc[0].hHeap, hWnd, plbw->plc[0].apli[i],    "") ;
  2219.            else
  2220.            if (    (lSetItemText(plbw->plc[0].hHeap, hWnd,    plbw->plc[0].apli[i],
  2221.                       albi[i].pszText) > plbw->cxItem) && (plbw->flStyle & LS_HORZSCROLL) )
  2222.                plbw->cxItem = plbw->plc[0].apli[i]->cxItem;
  2223.  
  2224.            plbw->plc[0].apli[i]->ulHandle =    albi[i].ulHandle;
  2225.            }
  2226.                /* Save the list    box length and refresh the    */
  2227.                /* list box                    */
  2228.  
  2229.        plbw->cItems    += (LONG)LONGFROMMP(mp1);
  2230.        RefreshList(plbw, 0L);
  2231.  
  2232.                /* Remove the exception handle since the    lazy    */
  2233.                /* pointer evaluation is    done            */
  2234.  
  2235.        DosUnsetExceptionHandler(&xcptregr);
  2236.        }
  2237.        else
  2238.        return(MRFROMLONG(TRUE));
  2239.        break;
  2240.  
  2241.    /*********************************************************************/
  2242.    /*  Extended    message:   LMX_SORT                    */
  2243.    /*               mp1 = MPFROMLONG(lDirection);        */
  2244.    /*               mp2 = 0L;                    */
  2245.    /*********************************************************************/
  2246.  
  2247.    case    LMX_SORT :
  2248.        switch (    LONGFROMMP(mp1)    )
  2249.        {
  2250.        case    LIT_SORTASCENDING :
  2251.            if ( plbw->cItems )
  2252.  
  2253.                /* Sort the list    in ascending order        */
  2254.  
  2255.            SortAscending(plbw->plc[0].apli, 0, plbw->cItems - 1);
  2256.            break;
  2257.  
  2258.        case    LIT_SORTDESCENDING :
  2259.            if ( plbw->cItems )
  2260.  
  2261.                /* Sort the list    in descending order        */
  2262.  
  2263.            SortDescending(plbw->plc[0].apli, 0,    plbw->cItems - 1);
  2264.            break;
  2265.  
  2266.        default :
  2267.            return(MRFROMLONG(TRUE));
  2268.        }
  2269.        break;
  2270.  
  2271.    /*********************************************************************/
  2272.    /*  Extended    message:   LMX_SELECTALL                */
  2273.    /*               mp1 = 0L;                    */
  2274.    /*               mp2 = 0L;                    */
  2275.    /*********************************************************************/
  2276.  
  2277.    case    LMX_SELECTALL :
  2278.        if ( plbw->cItems && (plbw->flStyle & (LS_MULTIPLESEL | LS_EXTENDEDSEL))    )
  2279.        {
  2280.        for ( i = 0;    i < plbw->cItems; i++ )
  2281.            if ( (plbw->plc[0].apli[i]->fl &    LI_SELECTED) ==    0UL )
  2282.            {
  2283.            SaveSelectState(0L, i);
  2284.            plbw->plc[0].apli[i]->fl |= LI_SELECTED;
  2285.            }
  2286.        mrNotifyOwner(plbw, LN_SELECT);
  2287.        RefreshList(plbw, 0L);
  2288.        }
  2289.        else
  2290.        return(MRFROMLONG(TRUE));
  2291.        break;
  2292.  
  2293.    /*********************************************************************/
  2294.    /*  Extended    message:   LMX_QUERYITEMCOUNT                */
  2295.    /*               mp1 = 0L;                    */
  2296.    /*               mp2 = 0L;                    */
  2297.    /*********************************************************************/
  2298.  
  2299.    case    LMX_QUERYITEMCOUNT :
  2300.        return(MRFROMLONG(plbw->cItems));
  2301.    }
  2302. return(0L);
  2303. }
  2304. #pragma    subtitle("   List Manager - Extended List Box Messages Procedure")
  2305. #pragma    page( )
  2306.  
  2307. /* --- mrChkBoxHandler --------------------------------- [ Public ] ---    */
  2308. /*                                    */
  2309. /*     This function is    used to    process    the extended messages for the    */
  2310. /*     list box    control    window check box support.            */
  2311. /*                                    */
  2312. /*     Upon Entry:                            */
  2313. /*                                    */
  2314. /*     HWND   hWnd; = Window Handle                    */
  2315. /*     ULONG  msg;  = PM Message                    */
  2316. /*     MPARAM mp1;  = Message Parameter    1                */
  2317. /*     MPARAM mp2;  = Message Parameter    2                */
  2318. /*                                    */
  2319. /*     Upon Exit:                            */
  2320. /*                                    */
  2321. /*     mrChkBoxHandler = Message Handling Result            */
  2322. /*                                    */
  2323. /* --------------------------------------------------------------------    */
  2324.  
  2325. MRESULT    EXPENTRY mrChkBoxHandler(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  2326.  
  2327. {
  2328. PBOOL         afl;           /* Flags Array            */
  2329. PLISTBOXWIN  plbw;           /* List Box Internal    Data Pointer    */
  2330. register INT i,    n;           /* Loop Counter            */
  2331. EXCEPTIONREGISTRATIONRECORD xcptregr;       /* Exception    Record        */
  2332.  
  2333. plbw = (PLISTBOXWIN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2334.  
  2335. switch ( msg )
  2336.    {
  2337.  
  2338.    /*********************************************************************/
  2339.    /*  Extended    message:   LMX_ADDARRAY                    */
  2340.    /*               mp1 = MPFROMLONG(iItem);            */
  2341.    /*               mp2 = MPFROMLONG(fSelect);            */
  2342.    /*********************************************************************/
  2343.  
  2344.    case    LMX_SETCHECK :
  2345.        if ( (LONG)LONGFROMMP(mp1) == LIT_NONE )
  2346.        {
  2347.        for ( i = 0;    i < plbw->cItems; i++ )
  2348.            if (plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2349.            {
  2350.            SaveSelectState(0L, i);
  2351.            plbw->plc[0].apli[i]->fl &= ~LI_CHECKED;
  2352.  
  2353.                /* Invert the rectangle of the entry to return    */
  2354.                /* it back to its normal    display    colour        */
  2355.  
  2356.            DrawSelection(plbw, i);
  2357.            }
  2358.        return(MRFROMLONG(TRUE));
  2359.        }
  2360.        else
  2361.                /* Check    to see that items within the list box    */
  2362.                /* and that the item requested is within    the    */
  2363.                /* range    of items                */
  2364.  
  2365.        if (    (LONG)LONGFROMMP(mp1) <    plbw->cItems )
  2366.            {
  2367.            if ( plbw->plc[0].apli[LONGFROMMP(mp1)]->fl & LI_CHECKED    )
  2368.            plbw->plc[0].apli[LONGFROMMP(mp1)]->fl &= ~LI_CHECKED;
  2369.            else
  2370.            plbw->plc[0].apli[LONGFROMMP(mp1)]->fl |= LI_CHECKED;
  2371.  
  2372.                /* Draw the updated item                */
  2373.  
  2374.            DrawSelection(plbw, (LONG)LONGFROMMP(mp1));
  2375.            mrNotifyOwner(plbw, LNX_CHECKED);
  2376.            return(MRFROMLONG(TRUE));
  2377.            }
  2378.        else
  2379.            return(MRFROMLONG(FALSE));
  2380.  
  2381.    /*********************************************************************/
  2382.    /*  Extended    message:   LMX_QUERYCHECK                */
  2383.    /*               mp1 = MPFROMLONG(iItemPrev);            */
  2384.    /*               mp2 = 0L;                    */
  2385.    /*********************************************************************/
  2386.  
  2387.    case    LMX_QUERYCHECK :
  2388.        if ( plbw->cItems )
  2389.        {
  2390.        if (    (LONG)(SHORT)SHORT1FROMMP(mp1) == LIT_FIRST )
  2391.            {
  2392.            for ( i = 0; i <    plbw->cItems; i++ )
  2393.            if (    plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2394.                return(MRFROMLONG(i));
  2395.  
  2396.            return(MRFROMLONG(LIT_NONE));
  2397.            }
  2398.        else
  2399.            if ( (LONG)(SHORT)SHORT1FROMMP(mp1) >= 0L )
  2400.            {
  2401.            for ( i = (LONG)(SHORT)SHORT1FROMMP(mp1) + 1; i < plbw->cItems; i++ )
  2402.                if ( plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2403.                return(MRFROMLONG(i));
  2404.  
  2405.            return(MRFROMLONG(LIT_NONE));
  2406.            }
  2407.            else
  2408.            return(MRFROMLONG(LIT_NONE));
  2409.        }
  2410.        else
  2411.        return(MRFROMLONG(LIT_NONE));
  2412.  
  2413.    /*********************************************************************/
  2414.    /*  Extended    message:   LMX_SETCHECKARRAY                */
  2415.    /*               mp1 = MPFROMLONG(cItems);            */
  2416.    /*               mp2 = MPFROMP(afl);                */
  2417.    /*********************************************************************/
  2418.  
  2419.    case    LMX_SETCHECKARRAY :
  2420.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2421.        {
  2422.                /* Register exception handler that is used for    */
  2423.                /* the lazy pointer validation tests        */
  2424.  
  2425.        xcptregr.prev_structure   = NULL;
  2426.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2427.  
  2428.        DosSetExceptionHandler(&xcptregr);
  2429.  
  2430.        if (    setjmp(jBuf) )
  2431.            {
  2432.                /* Remove the exception handle since the    lazy    */
  2433.                /* pointer evaluation is    done            */
  2434.  
  2435.            DosUnsetExceptionHandler(&xcptregr);
  2436.            return(0L);
  2437.            }
  2438.                /* Get the pointer to the item array        */
  2439.  
  2440.        afl = (PBOOL)PVOIDFROMMP(mp2);
  2441.  
  2442.        if (    plbw->cItems < LONGFROMMP(mp1) )
  2443.            n = plbw->cItems;
  2444.        else
  2445.            n = (LONG)LONGFROMMP(mp1);
  2446.  
  2447.                /* Loop through the list    of items and place each    */
  2448.                /* one within the list box.  If the list    box    */
  2449.                /* contains any items, append the new items to    */
  2450.                /* the end of the list.                */
  2451.  
  2452.        for ( i = 0;    i < n; i++ )
  2453.            if ( afl[i] )
  2454.            plbw->plc[0].apli[i]->fl |= LI_CHECKED;
  2455.            else
  2456.            plbw->plc[0].apli[i]->fl &= ~LI_CHECKED;
  2457.  
  2458.        RefreshList(plbw, 0L);
  2459.  
  2460.                /* Remove the exception handle since the    lazy    */
  2461.                /* pointer evaluation is    done            */
  2462.  
  2463.        DosUnsetExceptionHandler(&xcptregr);
  2464.        return(MRFROMLONG(n));
  2465.        }
  2466.        else
  2467.        return(0L);
  2468.  
  2469.    /*********************************************************************/
  2470.    /*  Extended    message:   LMX_QUERYCHECKARRAY                */
  2471.    /*               mp1 = MPFROMLONG(cItems);            */
  2472.    /*               mp2 = MPFROMP(afl);                */
  2473.    /*********************************************************************/
  2474.  
  2475.    case    LMX_QUERYCHECKARRAY :
  2476.        if ( (LONGFROMMP(mp1) > 0L) && PVOIDFROMMP(mp2) )
  2477.        {
  2478.                /* Register exception handler that is used for    */
  2479.                /* the lazy pointer validation tests        */
  2480.  
  2481.        xcptregr.prev_structure   = NULL;
  2482.        xcptregr.ExceptionHandler = &ListBoxExceptionHandler;
  2483.  
  2484.        DosSetExceptionHandler(&xcptregr);
  2485.  
  2486.        if (    setjmp(jBuf) )
  2487.            {
  2488.                /* Remove the exception handle since the    lazy    */
  2489.                /* pointer evaluation is    done            */
  2490.  
  2491.            DosUnsetExceptionHandler(&xcptregr);
  2492.            return(0L);
  2493.            }
  2494.                /* Get the pointer to the item array        */
  2495.  
  2496.        afl = (PBOOL)PVOIDFROMMP(mp2);
  2497.  
  2498.        if (    plbw->cItems < LONGFROMMP(mp1) )
  2499.            n = plbw->cItems;
  2500.        else
  2501.            n = (LONG)LONGFROMMP(mp1);
  2502.  
  2503.                /* Loop through the list    of items and place each    */
  2504.                /* one within the list box.  If the list    box    */
  2505.                /* contains any items, append the new items to    */
  2506.                /* the end of the list.                */
  2507.  
  2508.        for ( i = 0;    i < n; i++ )
  2509.            if ( plbw->plc[0].apli[i]->fl & LI_CHECKED )
  2510.            afl[i] = TRUE;
  2511.            else
  2512.            afl[i] = FALSE;
  2513.  
  2514.                /* Remove the exception handle since the    lazy    */
  2515.                /* pointer evaluation is    done            */
  2516.  
  2517.        DosUnsetExceptionHandler(&xcptregr);
  2518.        return(MRFROMLONG(n));
  2519.        }
  2520.        else
  2521.        return(0L);
  2522.    }
  2523. return(0L);
  2524. }
  2525. #pragma    subtitle("   List Manager   - Exception Handler Routine")
  2526. #pragma    page( )
  2527.  
  2528. /* --- ListBoxExceptionHandler ------------------------    [ Private ] ---    */
  2529. /*                                    */
  2530. /*     This function is    used process exceptions    under 2.0 and to,    */
  2531. /*     depending on the    exception, provide a method of performing    */
  2532. /*     lazy pointer validation for the data types.            */
  2533. /*                                    */
  2534. /*     Upon Entry:                            */
  2535. /*                                    */
  2536. /*     PEXCEPTIONREPORTRECORD        pxcptrepr; = Report    Record        */
  2537. /*     PEXCEPTIONREGISTRATIONRECORD pxcptregr; = Registration Record    */
  2538. /*     PCONTEXTRECORD            pcr;       = Context Record        */
  2539. /*     PVOID                sysinfo;   = System    Reserved    */
  2540. /*                                    */
  2541. /*     Upon Exit:                            */
  2542. /*                                    */
  2543. /*     ListBoxExceptionHandler = Exception Handling Value        */
  2544. /*                                    */
  2545. /* --------------------------------------------------------------------    */
  2546.  
  2547. APIRET APIENTRY    ListBoxExceptionHandler(PEXCEPTIONREPORTRECORD pxcptrepr,
  2548.                     PEXCEPTIONREGISTRATIONRECORD pxcptregr,
  2549.                     PCONTEXTRECORD pcr, PVOID sysinfo)
  2550.  
  2551. {
  2552. #pragma    info(nopar)
  2553.  
  2554. if ( EH_EXIT_UNWIND & pxcptrepr->fHandlerFlags )
  2555.    return(XCPT_CONTINUE_SEARCH);
  2556.  
  2557. if ( EH_UNWINDING & pxcptrepr->fHandlerFlags )
  2558.    return(XCPT_CONTINUE_SEARCH);
  2559.  
  2560. if ( EH_NESTED_CALL & pxcptrepr->fHandlerFlags )
  2561.    return(XCPT_CONTINUE_SEARCH);
  2562.  
  2563. if ( pxcptrepr->ExceptionNum ==    XCPT_ACCESS_VIOLATION )
  2564.    longjmp((INT    *)jBuf,    1);
  2565.  
  2566. return(XCPT_CONTINUE_SEARCH);
  2567. }
  2568.