home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lstbx1.zip / LISTMGR.C < prev    next >
C/C++ Source or Header  |  1994-01-07  |  77KB  |  2,239 lines

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