
#include "windows.h"
#include "vlistint.h"
#include "string.h"
#include "draw3d.h"
#include "memory.h"

#define _LB_MOUSESCROLL         0x0118

#ifdef WIN32
BOOL  fWIN32s;
#endif

extern HINSTANCE hLib;
BOOL WINAPI RegisterVListBox(VOID);

BOOL WINAPI RegisterVListBox() {
   HINSTANCE       hInstance = hLib;
   static BOOL     bRegistered=FALSE;
   WNDCLASS        wndcls;

   if (!bRegistered) {
       wndcls.style         = CS_DBLCLKS| CS_GLOBALCLASS|CS_PARENTDC;
       wndcls.lpfnWndProc   = VListBoxWndProc;
       wndcls.cbClsExtra    = 0;
       wndcls.cbWndExtra    = 8;
       wndcls.hInstance     = hInstance;
       wndcls.hIcon         = NULL;
       wndcls.hCursor       = LoadCursor(NULL, IDC_ARROW);
       wndcls.hbrBackground =  (HBRUSH)(COLOR_WINDOW+1);
       wndcls.lpszMenuName  = NULL;
       wndcls.lpszClassName = (LPSTR)VLIST_CLASSNAME;
       bRegistered=RegisterClass(&wndcls);
   }

#ifdef WIN32
   fWIN32s = ((DWORD)GetVersion() & 0x80000000) ? TRUE : FALSE;
#endif
   return bRegistered;
}

VOID FAR RegisterVlist() {   // vincent: FARPROC is added
  static BOOL regd = FALSE;
  if (!regd) {
    RegisterVListBox();
    regd = TRUE;
  }
}


LRESULT EXPORT WINAPI VListBoxWndProc(HWND hwnd, UINT message,
                                      WPARAM wParam, LPARAM lParam) {
  LONG lRetVal;
  LONG par1;
  LONG par2;
  LPVLBOX lpVLBox;

  /* Get the lpVLBox for the given window now since we will use it a lot in
   * various handlers. This was stored using SetWindowLong(hwnd,0,pVLBox) when
   * we initially created the Virtual List Box control.
   */
#ifdef WIN32
   lpVLBox = (LPVLBOX) GetWindowLong(hwnd,0);
   if (message != WM_NCCREATE && (DWORD)lpVLBox == (DWORD)-1)
#else
   lpVLBox = (LPVLBOX) GetWindowLong(hwnd,0);
   if (message != WM_NCCREATE && (WORD)lpVLBox == (WORD)-1)
#endif
       // The lpVLBox was destroyed and this is a rogue message to be ignored.
       return(0L);

  /* Dispatch the various messages we can receive */
  //
  // check for ListBox message coming from application
  // and forward them onto the listbox itself...
  //
#ifdef WIN32  
  if ( ((fWIN32s == TRUE) && (message >= WM_USER && message < VLB_MSGMIN) ) ||  // WIN32s version 
       ((fWIN32s == FALSE) && (message >= LB_ADDSTRING && message < LB_MSGMAX)) // NT version    
     ) {

     return(SendMessage(lpVLBox->hwndList, message, wParam, lParam));
  }
#endif

  switch (message) {
    case VLB_INITIALIZE:
      SetScrollRange(lpVLBox->hwndList, SB_VERT, 0, 100, TRUE);
      lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
      SendMessage(lpVLBox->hwndParent, VLB_RANGE, 0, (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
      if ( lpVLBox->vlbStruct.nStatus == VLB_OK ) {
         lpVLBox->lNumLogicalRecs = lpVLBox->vlbStruct.lIndex;
      }
      else {
         lpVLBox->lNumLogicalRecs = -1L;
         lpVLBox->wFlags = lpVLBox->wFlags | USEDATAVALUES;
      }

      if (lpVLBox->styleSave & VLBS_USEDATAVALUES )
         lpVLBox->wFlags |= USEDATAVALUES;

      if (lpVLBox->lNumLogicalRecs != 0 && lpVLBox->nLines != 0)
         VLBFirstPage(lpVLBox);

      lpVLBox->lSelItem = -1L;

      return VLB_OK;

      break;

    case WM_VSCROLL:
#ifdef WIN32
       switch(LOWORD(wParam)) {
#else
       switch(wParam) {
#endif
          case SB_LINEDOWN:
              VLBScrollDownLine(lpVLBox);
              SetSelectedItem(lpVLBox);
          break;

          case SB_PAGEDOWN:
              VLBScrollDownPage(lpVLBox, 0);
              SetSelectedItem(lpVLBox);
          break;

          case SB_LINEUP:
              VLBScrollUpLine(lpVLBox);
              SetSelectedItem(lpVLBox);
          break;

          case SB_PAGEUP:
              VLBScrollUpPage(lpVLBox, 0);
              SetSelectedItem(lpVLBox);
          break;

          case SB_TOP:
              VLBFirstPage(lpVLBox);
              SetSelectedItem(lpVLBox);
          break;

          case SB_BOTTOM:
              VLBLastPage(lpVLBox);
              SetSelectedItem(lpVLBox);
          break;

          case SB_THUMBPOSITION:
            {
              int nPos;
#ifdef WIN32
              nPos = HIWORD(wParam);
#else
              nPos = LOWORD(lParam);
#endif
              if ( nPos == 0 ) {
                 VLBFirstPage(lpVLBox);
                 break;
              }
              else if ( nPos == 100 ) {
                 VLBLastPage(lpVLBox);
                 break;
              }

              if ( lpVLBox->wFlags & USEDATAVALUES ) {
                    if ( VLBFindPos(lpVLBox, nPos) )
                        return VLB_ERR;
                    else
                        SetSelectedItem(lpVLBox);
              }
              else {
                 if ( VLBFindPage(lpVLBox,
#ifdef WIN32
                 (((LONG)HIWORD(wParam)
#else
                 (((LONG)LOWORD(lParam)
#endif
                   *(lpVLBox->lNumLogicalRecs-lpVLBox->nLines+1))/100L),
                      TRUE))
                    return VLB_ERR;
                 else
                    SetSelectedItem(lpVLBox);
              }
            }
          break;

       }
       return((LONG)TRUE);
       break;

    case WM_COMMAND:
      /* So that we can handle notification messages from the listbox.
       */
#ifdef WIN32
      if ( HIWORD(wParam) == LBN_SELCHANGE ) {
#else
      if ( HIWORD(lParam) == LBN_SELCHANGE ) {
#endif
         SetSelectedItem(lpVLBox);
      }
#ifdef WIN32
      else if (HIWORD(wParam) == LBN_SELCANCEL) {
#else
      else if (HIWORD(lParam) == LBN_SELCANCEL) {
#endif
         lpVLBox->lSelItem = -1L;
      }
      if (lpVLBox->styleSave & VLBS_NOTIFY ) {
#ifdef WIN32
         return(VLBParentMessageHandler(lpVLBox, message,
                                        (WPARAM)MAKELONG(lpVLBox->nId,
                                        HIWORD(wParam)), lParam));

#else
         return(VLBParentMessageHandler(lpVLBox, message,
                                        (WPARAM)(WORD)lpVLBox->nId, lParam));
#endif
      }
      else {
         return TRUE;
      }
      break;

    case WM_CHARTOITEM: {
           long lRet;

           if (lpVLBox->styleSave & VLBS_WANTKEYBOARDINPUT ) {
              lRet = VLBParentMessageHandler(lpVLBox, WM_CHARTOITEM,
                                             wParam, lParam);
           }
           else {
              lRet = -1;
           }

           return lRet;
        }
        break;

    case WM_VKEYTOITEM: {
           long lRet;

           if (lpVLBox->styleSave & VLBS_WANTKEYBOARDINPUT ) {
              lRet = VLBParentMessageHandler(lpVLBox, WM_VKEYTOITEM,
                                             wParam, lParam);
           }
           else {
              lRet = -1;
           }

           if ( lRet == -1 ) {
#ifdef WIN32
       switch(LOWORD(wParam)) {
#else
       switch(wParam) {
#endif
                 case VK_DOWN:
                    vlbLineDn(lpVLBox);
                    lRet = -2L;
                 break;

                 case VK_UP:
                    vlbLineUp(lpVLBox);
                    lRet = -2L;
                 break;

                 case VK_PRIOR:
                     vlbPGUP(lpVLBox);
                    lRet = -2L;
                 break;

                 case VK_NEXT:
                     vlbPGDN(lpVLBox);
                    lRet = -2L;
                 break;

                 case VK_HOME:
                     VLBFirstPage(lpVLBox);
                     SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                     SetSelectedItem(lpVLBox);
                     lRet = -2L;
                 break;

                 case VK_END:
                  {
                     int nLastLine;

                     if ( (lpVLBox->nLines-1) < lpVLBox->nCountInBox )
                        nLastLine = lpVLBox->nLines-1;
                     else
                        nLastLine = lpVLBox->nCountInBox-1;

                     VLBLastPage(lpVLBox);
                     SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                 nLastLine, 0L);
                     SetSelectedItem(lpVLBox);
                     lRet = -2L;
                  }
                 break;

                 default:
                    return lRet;
              }
              SendMessage(lpVLBox->hwndParent, WM_COMMAND,
                          lpVLBox->nId, MAKELPARAM(hwnd, LBN_SELCHANGE));
           }
           return lRet;
        }
        break;

    case _LB_MOUSESCROLL:
       {
         //
         // The user is holding the mouse down outside the LB....
         // Scroll the VLB as needed.
         //
         // Dont need to LB_SETCURSEL since the LB is going to do this for us.
         //
         int nSelected;

         nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
         if ( nSelected == lpVLBox->nLines-1 ) {
            VLBScrollDownLine(lpVLBox);
            SetSelectedItem(lpVLBox);
         }
         else if ( nSelected == 0 ) {
            VLBScrollUpLine(lpVLBox);
            SetSelectedItem(lpVLBox);
         }
         //
         // Values doesn't mean much since this messsage is passed back to
         // original LB proc
         //
         return 0L;
      }
      break;

    case WM_CREATE:
      /* wParam - not used
         lParam - Points to the CREATESTRUCT data structure for the window.
       */
      return(VLBCreateHandler(lpVLBox, hwnd, (LPCREATESTRUCT)lParam));
      break;

    case WM_ERASEBKGND:
      /* Just return 1L so that the background isn't erased */
      return((LONG)TRUE);
      break;

    case WM_GETFONT:
       return((LONG)(lpVLBox->hFont));
       break;

    case WM_GETDLGCODE:
      /* wParam - not used
         lParam - not used */
      return((LONG)(DLGC_WANTCHARS | DLGC_WANTARROWS));
      break;

    case WM_SETFONT:
#ifdef WIN32
      VLBSetFontHandler(lpVLBox, (HANDLE)wParam, wParam);
#else
      VLBSetFontHandler(lpVLBox, (HANDLE)wParam, LOWORD(lParam));
#endif
      break;

    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_KEYDOWN:
       // Set the focus to the Virtual List Box if we get a mouse click
       // or key press on the parent window.
       SetFocus(lpVLBox->hwndList);
       SendMessage(lpVLBox->hwndList, message, wParam, lParam);
      break;

    case WM_NCDESTROY:
      /* wParam - used by DefWndProc called within VLBNcDestroyHandler
         lParam - used by DefWndProc called within VLBNcDestroyHandler */
      VLBNcDestroyHandler(hwnd, lpVLBox, wParam, lParam);
      break;

    case WM_KILLFOCUS:
          if ( (HWND) wParam != lpVLBox->hwndList )
              lpVLBox->wFlags  &= ~HASFOCUS;

      break;

    case WM_SETFOCUS:
        {
          int i;
          lpVLBox->wFlags  |= HASFOCUS;
          if ( ! (lpVLBox->wFlags & PARENTFOCUS) ) {
             if ( (i=vlbInVLB(lpVLBox, lpVLBox->lSelItem)) >= 0 ) {
                lpVLBox->wFlags &= ~PARENTFOCUS;
                SetFocus(lpVLBox->hwndList);
             }
             else {
                lpVLBox->wFlags |= PARENTFOCUS;
             }
          }
        }
      break;

    case WM_SETREDRAW:
      /* wParam - specifies state of the redraw flag. nonzero = redraw
         lParam - not used */
      if ( wParam) {
         vlbRedrawOn(lpVLBox);
      }
      else {
         vlbRedrawOff(lpVLBox);
      }
      return TRUE;
      break;

    case WM_ENABLE:
      /* Invalidate the rect to cause it to be drawn in grey for its disabled
       * view or ungreyed for non-disabled view.
       */
      InvalidateRect(lpVLBox->hwnd, NULL, FALSE);
      /* Enable/disable the listbox window
       */
      EnableWindow(lpVLBox->hwndList, wParam);
      // EnableWindow(lpVLBox->hwndScroll, wParam);
      break;

    case WM_SIZE:
      /* wParam - defines the type of resizing fullscreen, sizeiconic,
                  sizenormal etc.
         lParam - new width in LOWORD, new height in HIGHWORD of client area */
      if (!LOWORD(lParam) || !HIWORD(lParam) || !lpVLBox->hwndList)
          /* If being sized to a zero width or to a zero height or we aren't
           * fully initialized, just return.
           */
             return(0);
      VLBSizeHandler(lpVLBox, 0);
      break;

    case VLB_FINDSTRING:
    case VLB_FINDSTRINGEXACT:
    case VLB_SELECTSTRING:
       {
          VLBSTRUCT FAR *lpvlbInStruct;
          UINT  ReturnMsg;

          switch (message)
          {
            case VLB_FINDSTRING:
                ReturnMsg = VLBR_FINDSTRING;
                break;

            case VLB_FINDSTRINGEXACT:
                ReturnMsg = VLBR_FINDSTRINGEXACT;
                break;

            case VLB_SELECTSTRING:
                ReturnMsg = VLBR_FINDSTRINGEXACT;
                break;
          }

          lpvlbInStruct = (LPVLBSTRUCT)lParam;
          lpVLBox->vlbStruct.lIndex        = lpvlbInStruct->lIndex;
          lpVLBox->vlbStruct.lData         = lpvlbInStruct->lData;
          lpVLBox->vlbStruct.lpFindString  = lpvlbInStruct->lpFindString;
          lpVLBox->vlbStruct.lpTextPointer = NULL;

          lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
          SendMessage(lpVLBox->hwndParent, ReturnMsg, 0,
                      (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          if ( lpVLBox->vlbStruct.nStatus == VLB_OK ) {
             if ( lpVLBox->wFlags & USEDATAVALUES )
                lRetVal = lpVLBox->vlbStruct.lData;
             else
                lRetVal = lpVLBox->vlbStruct.lIndex;

             if ( message != VLB_SELECTSTRING ) {
                return lRetVal;
             }

             if (lpVLBox->wFlags & USEDATAVALUES) {
                // Strings or search for data
                int i;
                if ((i = vlbFindData(lpVLBox, lpVLBox->vlbStruct.lData))
                                                           != LB_ERR) {
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, i, 0L);
                    SetSelectedItem(lpVLBox);
                    return lRetVal;
                }
                else {
                   if (VLBFindPage(lpVLBox, lpVLBox->vlbStruct.lData, TRUE))
                        return VLB_ERR;

                   SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                   SetSelectedItem(lpVLBox);
                   return lRetVal;
                }
             }
             else {
                //
                // Is this item in the list box now ??
                //
                if (lpVLBox->vlbStruct.lIndex >= lpVLBox->lToplIndex &&
                    lpVLBox->vlbStruct.lIndex <= (lpVLBox->lToplIndex+
                                           (LONG)(lpVLBox->nCountInBox)-1)) {
                   int nItemNum;
                   nItemNum = (int)(lpVLBox->vlbStruct.lIndex -
                                          lpVLBox->lToplIndex);
                   SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                               nItemNum, 0L);
                   SetSelectedItem(lpVLBox);
                   return lRetVal;
                }
                //
                // OK Adjust to show item
                //
                if ( VLBFindPage(lpVLBox, lpVLBox->vlbStruct.lIndex, TRUE) )
                    return VLB_ERR;

                SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                SetSelectedItem(lpVLBox);
                return lRetVal;
             }
          }
          else
             return VLB_ERR;
       }
      break;

    case VLB_RESETCONTENT:
      SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);
      SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
      lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
      SendMessage(lpVLBox->hwndParent, VLB_RANGE, 0,
                  (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
      if ( lpVLBox->vlbStruct.nStatus == VLB_OK )
         lpVLBox->lNumLogicalRecs = lpVLBox->vlbStruct.lIndex;
      else {
         lpVLBox->lNumLogicalRecs = -1L;
         lpVLBox->wFlags |= USEDATAVALUES;
      }

      if ( lpVLBox->lNumLogicalRecs != 0 )
         VLBFirstPage(lpVLBox);

      lpVLBox->lSelItem = -1L;

      return VLB_OK;
      break;

    case VLB_SETCURSEL:
       // wParam Has Set Option:
       //   VLBC_FIRST
       //   VLBC_PREV
       //   VLBC_NEXT
       //   VLBC_LAST
       //   VLBC_FINDITEM
       //
       //  lParam has the item number or item data
       if ( lParam == -1L ) {
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WORD)-1, 0L);
              lpVLBox->lSelItem = -1L;
              return ( -1L );
       }
       else {
          par1 = wParam;
          par2 = lParam;
          lRetVal = vlbSetCurSel(par1, par2, lpVLBox);
          return (lRetVal);
       }
       break;

    case VLB_UPDATEPAGE:
         lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
         SendMessage(lpVLBox->hwndParent, VLB_RANGE, 0,
                     (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
         if ( lpVLBox->vlbStruct.nStatus == VLB_OK ) {
            lpVLBox->lNumLogicalRecs = lpVLBox->vlbStruct.lIndex;
         }
         else {
            lpVLBox->lNumLogicalRecs = -1L;
            lpVLBox->wFlags |= USEDATAVALUES;
         }

         if ( lpVLBox->lNumLogicalRecs == 0L ) {
            SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);
            SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
            lpVLBox->lSelItem = -1L;
         }
         else if (lpVLBox->wFlags & USEDATAVALUES ) {
             if (VLBFindPage(lpVLBox,
                             SendMessage(lpVLBox->hwndList,
                                         LB_GETITEMDATA, 0, 0L), FALSE))
                return VLB_ERR;
         }
         else if (lpVLBox->lNumLogicalRecs <= lpVLBox->nLines) {
            VLBFirstPage(lpVLBox);
         }
         else {
             if ( VLBFindPage(lpVLBox, lpVLBox->lToplIndex, FALSE) )
                return VLB_ERR;
         }
       break;

    case VLB_PAGEUP:
         VLBScrollUpPage(lpVLBox, wParam);
         break;

    case VLB_PAGEDOWN:
         VLBScrollDownPage(lpVLBox, wParam);
         break;

    case VLB_GETCURSEL:
         return lpVLBox->lSelItem;
         break;

    case VLB_GETLINES:
         return (LONG)lpVLBox->nLines;
         break;

    case VLB_GETITEMDATA:
        {
          LPVLBSTRUCT lpvlbInStruct;
          int i;
          LPARAM SendlParam;


          lpvlbInStruct = (LPVLBSTRUCT)lParam;

          if (lpVLBox->wFlags & USEDATAVALUES) {
             SendlParam = lpvlbInStruct->lData;
          }
          else {
             SendlParam = lpvlbInStruct->lIndex;
          }

          if ( (i=vlbInVLB(lpVLBox, SendlParam)) >= 0 ) {
             return(SendMessage(lpVLBox->hwndList, LB_GETITEMDATA, i, 0L));
          }
          else {
             lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = SendlParam;
             lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
             SendMessage(lpVLBox->hwndParent, VLBR_GETITEMDATA, 0,
                         (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
             if ( lpVLBox->vlbStruct.nStatus == VLB_OK )
                return lpVLBox->vlbStruct.lData;
             else
                return VLB_ERR;
          }
        }
        break;

    case VLB_GETCOUNT:
      return lpVLBox->lNumLogicalRecs;

    case VLB_GETTEXT:
        {
          LPVLBSTRUCT lpvlbInStruct;
          int i;
          LPARAM SendlParam;

          lpvlbInStruct = (LPVLBSTRUCT)lParam;

          if (lpVLBox->wFlags & USEDATAVALUES) {
             SendlParam = lpvlbInStruct->lData;
          }
          else {
             SendlParam = lpvlbInStruct->lIndex;
          }

          if ( (i=vlbInVLB(lpVLBox, SendlParam)) >= 0 ) {
             return(SendMessage(lpVLBox->hwndList, LB_GETTEXT, i,
                                (LPARAM)lpvlbInStruct->lpTextPointer));
          }
          else {
             lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = SendlParam;
             lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
             SendMessage(lpVLBox->hwndParent, VLBR_GETTEXT, 0,
                         (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
             if ( lpVLBox->vlbStruct.nStatus == VLB_OK ) {
                _fstrcpy(lpvlbInStruct->lpTextPointer,
                         lpVLBox->vlbStruct.lpTextPointer);
                return _fstrlen(lpVLBox->vlbStruct.lpTextPointer);
             }
             else
                return VLB_ERR;
          }
        }
        break;

    case VLB_GETTEXTLEN:
        {
          LPVLBSTRUCT lpvlbInStruct;
          int i;
          LPARAM SendlParam;

          lpvlbInStruct = (LPVLBSTRUCT)lParam;

          if (lpVLBox->wFlags & USEDATAVALUES) {
             SendlParam = lpvlbInStruct->lData;
          }
          else {
             SendlParam = lpvlbInStruct->lIndex;
          }

          if ( (i=vlbInVLB(lpVLBox, SendlParam)) >= 0 ) {
             return(SendMessage(lpVLBox->hwndList, LB_GETTEXTLEN, i, 0L));
          }
          else {
             lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = SendlParam;
             lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
             return SendMessage(lpVLBox->hwndParent, VLBR_GETTEXTLEN, 0,
                                (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          }
        }
        break;

    case VLB_SETITEMDATA:
        {
          LPVLBSTRUCT lpvlbInStruct;
          int i;
          LPARAM SendlParam;

          lpvlbInStruct = (LPVLBSTRUCT)lParam;

          if (lpVLBox->wFlags & USEDATAVALUES) {
             SendlParam = lpvlbInStruct->lData;
          }
          else {
             SendlParam = lpvlbInStruct->lIndex;
          }

          if ( (i=vlbInVLB(lpVLBox, SendlParam)) >= 0 ) {
             return(SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, i,
                                (LPARAM)lpvlbInStruct->lIndex));
          }
          else return VLB_ERR;
        }
        break;

    case VLB_SETITEMHEIGHT:
          return SendMessage(lpVLBox->hwndList, LB_SETITEMHEIGHT, 0, lParam);
        break;

    case VLB_GETITEMHEIGHT:
          return SendMessage(lpVLBox->hwndList, LB_GETITEMHEIGHT, 0, 0L);
        break;

    case VLB_GETITEMRECT:
        {
          LPVLBSTRUCT lpvlbInStruct;
          int i;
          LPARAM SendlParam;

          lpvlbInStruct = (LPVLBSTRUCT)lParam;

          if (lpVLBox->wFlags & USEDATAVALUES) {
             SendlParam = lpvlbInStruct->lData;
          }
          else {
             SendlParam = lpvlbInStruct->lIndex;
          }

          if ( (i=vlbInVLB(lpVLBox, SendlParam)) >= 0 ) {
             return(SendMessage(lpVLBox->hwndList, LB_GETITEMRECT, i,
                                (LPARAM)lpvlbInStruct->lpTextPointer));
          }
          else return VLB_ERR;
        }
        break;

    case VLB_GETHORIZONTALEXTENT:
          return SendMessage(lpVLBox->hwndList, LB_GETHORIZONTALEXTENT, 0, 0L);
        break;

    case VLB_SETHORIZONTALEXTENT:
        {
          int nOrigin;
          RECT rc;
          int  nScrollBar;
          SendMessage(lpVLBox->hwndList, LB_GETITEMRECT, 0,
                      (LPARAM)(LPRECT)&rc);
          nOrigin = rc.left;
          GetClientRect(lpVLBox->hwndList, &rc);
          nScrollBar = max((int)wParam - (rc.right - rc.left),0);
          if (nOrigin || nScrollBar) {
             if (lpVLBox->styleSave & VLBS_DISABLENOSCROLL)
                EnableScrollBar(lpVLBox->hwndList, SB_HORZ, ESB_ENABLE_BOTH);
             else {
                if (!lpVLBox->bHScrollBar) {
                   lpVLBox->bHScrollBar = TRUE;
                   ShowScrollBar(lpVLBox->hwndList, SB_HORZ, TRUE);
                   VLBCountLines(lpVLBox);
                }
             }
          }
          else {
             if (lpVLBox->styleSave & VLBS_DISABLENOSCROLL)
                EnableScrollBar(lpVLBox->hwndList, SB_HORZ, ESB_DISABLE_BOTH);
             else {
                if (lpVLBox->bHScrollBar) {
                   lpVLBox->bHScrollBar = FALSE;
                   ShowScrollBar(lpVLBox->hwndList, SB_HORZ, FALSE);
                   VLBCountLines(lpVLBox);
                }
             }
          }
          return SendMessage(lpVLBox->hwndList,
                             LB_SETHORIZONTALEXTENT, wParam, 0L);
        }
        break;

    case VLB_SETTOPINDEX:
        {
          int i, nScroll;
          if ( (i=vlbInVLB(lpVLBox, lParam)) > 0 ) {
             nScroll = (int)(-1*(lpVLBox->nLines-i));
             VLBScrollDownPage(lpVLBox, nScroll);
          }
          else if ( lpVLBox->wFlags & USEDATAVALUES ) {
             if ( VLBFindPage(lpVLBox, lParam, TRUE ))
                return VLB_ERR;
          }
          else {
             if ( VLBFindPage(lpVLBox, lParam, TRUE) )
                return VLB_ERR;
          }
        }
        break;

    case VLB_GETTOPINDEX:
          if ( lpVLBox->wFlags & USEDATAVALUES )
             return SendMessage(lpVLBox->hwndList, LB_GETITEMDATA, 0, 0L);
          else
             return lpVLBox->lToplIndex;
        break;   
        
    case WM_CTLCOLOR:
         if ( lpVLBox->styleSave & VLBS_3DFRAME ) { 
            HBRUSH hBr;
            hBr = Draw3dCtlColor(CTLCOLOR_LISTBOX, wParam, lParam);
            if (hBr != (HBRUSH) FALSE) {
               return ((LRESULT) hBr);
            }
         }
         return DefWindowProc(hwnd, message, wParam, lParam);
        break;
                  
    case WM_PAINT:  
         DefWindowProc(hwnd, message, wParam, lParam);
         if ( lpVLBox->styleSave & VLBS_3DFRAME ) {
            RC rc;
            HDC hdc;          
            GetWindowRect(hwnd, (LPRECT) &rc);
            ScreenToClient(lpVLBox->hwndParent, (LPPOINT) &rc);
            ScreenToClient(lpVLBox->hwndParent, (LPPOINT) &rc+1);
            hdc = GetDC(lpVLBox->hwndParent );  
            Draw3dInsetRect(hdc, &rc, DR3ALL);
            ReleaseDC(lpVLBox->hwndParent,hdc); // Ron 11/23/93 
         }     
         break;              
      
    case WM_MEASUREITEM:
    case WM_DELETEITEM:
    case WM_DRAWITEM:
    case WM_COMPAREITEM:
      return(VLBMessageItemHandler(lpVLBox, message, (LPSTR)lParam));
      break;

    case WM_NCCREATE:
      /* wParam - Contains a handle to the window being created
         lParam - Points to the CREATESTRUCT data structure for the window.
       */
      return(VLBNcCreateHandler(hwnd, (LPCREATESTRUCT)lParam));
      break;

    default:
#ifndef WIN32    
      if ( message >= WM_USER )
         return(SendMessage(lpVLBox->hwndList, message, wParam, lParam));
      else
#endif      
         return DefWindowProc(hwnd, message, wParam, lParam);
      break;

  } /* switch (message) */

  return((LONG)(LONG)TRUE);
} /* VListBoxWndProc */


LONG VLBMessageItemHandler( LPVLBOX lpVLBox,  UINT message, LPSTR lpfoo) {
/*
 * effects: Handles WM_DRAWITEM,WM_MEASUREITEM,WM_DELETEITEM,WM_COMPAREITEM
 * messages from the listbox.
 */
  /*
   * Send the <foo>item message back to the application after changing some
   * parameters to their Virtual List Box specific versions.
   */
  long lRetVal;

  ((LPMEASUREITEMSTRUCT)lpfoo)->CtlType = ODT_LISTBOX;
#ifdef WIN32
  ((LPMEASUREITEMSTRUCT)lpfoo)->CtlID   = (DWORD)lpVLBox->nId;
#else
  ((LPMEASUREITEMSTRUCT)lpfoo)->CtlID   = (WORD)lpVLBox->nId;
#endif

  if (message == WM_DRAWITEM)
      ((LPDRAWITEMSTRUCT)lpfoo)->hwndItem    = lpVLBox->hwnd;
  else if (message == WM_DELETEITEM)
      ((LPDELETEITEMSTRUCT)lpfoo)->hwndItem  = lpVLBox->hwnd;
  else if (message == WM_COMPAREITEM)
      ((LPCOMPAREITEMSTRUCT)lpfoo)->hwndItem  = lpVLBox->hwnd;

  lRetVal = SendMessage(lpVLBox->hwndParent, message,
                    (WPARAM)lpVLBox->nId, (LPARAM)lpfoo);

  if (message == WM_MEASUREITEM ) {
     // Size the list box based on height in message
     VLBSizeHandler( lpVLBox , ((LPMEASUREITEMSTRUCT)lpfoo)->itemHeight);
  }
  return lRetVal;
}


LONG VLBParentMessageHandler( LPVLBOX lpVLBox, UINT message,
                              WPARAM wParam, LPARAM lParam) {
  return SendMessage(lpVLBox->hwndParent,
                     message,
                     wParam,
                     MAKELPARAM(lpVLBox->hwnd, HIWORD(lParam)));
}

int vlbInVLB( LPVLBOX lpVLBox, LONG lData) {
   int i;
   if (lpVLBox->wFlags & USEDATAVALUES) {
      if ((i=vlbFindData(lpVLBox, lData)) != LB_ERR) {
        return i;
      }
      else {
        return  VLB_ERR;
      }
   }
   else {
      if ( lData >= lpVLBox->lToplIndex &&
           lData <= (lpVLBox->lToplIndex+(LONG)(lpVLBox->nCountInBox)-1)) {
        return (int) (lData - lpVLBox->lToplIndex);
      }
      else {
        return  VLB_ERR;
      }
   }
}

int vlbFindData( LPVLBOX lpVLBox, LONG lData) {
   int i = 0;
   while ( i < lpVLBox->nCountInBox ) {
      if ( SendMessage(lpVLBox->hwndList, LB_GETITEMDATA, i, 0L) == lData )
         return i;
      i++;
   }
   return VLB_ERR;
}

void vlbRedrawOff(LPVLBOX lpVLBox) {
     lpVLBox->nvlbRedrawState--;
     if ( lpVLBox->nvlbRedrawState == 0 ) {
        SendMessage(lpVLBox->hwndList, WM_SETREDRAW, 0, 0L);
     }
}

void vlbRedrawOn(LPVLBOX lpVLBox) {
     lpVLBox->nvlbRedrawState++;
     if ( lpVLBox->nvlbRedrawState == 1 ) {
        SendMessage(lpVLBox->hwndList, WM_SETREDRAW, 1, 0L);
        InvalidateRect(lpVLBox->hwnd, NULL, FALSE);
     }
}


//
// List Box subclass function
//

static int inSubClass = FALSE;

LRESULT  EXPORT WINAPI LBSubclassProc(HWND hwnd, UINT message,
                                      WPARAM wParam, LPARAM lParam) {
    LRESULT lrTemp;
    LPVLBOX lpVLBox;

    switch (message) {
    case WM_VSCROLL:
        //
        // Handle all the scrolling in the Vlist proc
        //
        return SendMessage(GetParent(hwnd), message, wParam, lParam);

    case _LB_MOUSESCROLL:
        //
        // Check for scroll then pass message on the the LB
        //
        SendMessage(GetParent(hwnd), message, wParam, lParam);
      break;

    default:
        break;
    }

    //
    // call the old window proc
    //
#ifdef WIN32
   lpVLBox = (LPVLBOX) GetWindowLong(GetParent(hwnd),0);
#else
   lpVLBox = (LPVLBOX) GetWindowLong(GetParent(hwnd),0);
#endif

    if ( message == WM_SETFOCUS ) {
          lpVLBox->wFlags  |= HASFOCUS;
    }

    lrTemp = CallWindowProc((FARPROC)(WNDPROC)(lpVLBox->lpfnLBWndProc) ,
                            hwnd, message, (WPARAM) wParam, (LPARAM)lParam);
    if (inSubClass) return (lrTemp); // firewall

    // Modified by Ron Lunde, 11/5/93, to support hotspot testing of
    // mouse clicks, and fix a problem (just Borland C++?) with page up/down
    // pass message on to parent window (also), for special handling
    if (message == WM_LBUTTONUP || message == WM_LBUTTONDBLCLK) {
       inSubClass = TRUE;
       SendMessage(lpVLBox->hwndParent, message, wParam, (LPARAM)lParam);
       inSubClass = FALSE;
    }
    if (message == WM_KEYUP) {
       if(wParam == VK_NEXT) {
          inSubClass = TRUE;
          vlbPGDN(lpVLBox);
          inSubClass = FALSE;
       }
       else if (wParam == VK_PRIOR) {
        inSubClass = TRUE;
        vlbPGUP(lpVLBox);
        inSubClass = FALSE;
       }
       else if (wParam == VK_HOME) {
        inSubClass = TRUE;
        VListBoxWndProc(GetParent(hwnd), WM_VKEYTOITEM, VK_HOME, 0L);
        inSubClass = FALSE;
       }
       else if (wParam == VK_END) {
        inSubClass = TRUE;
        VListBoxWndProc(GetParent(hwnd), WM_VKEYTOITEM, VK_END, 0L);
        inSubClass = FALSE;
       }
    }
    return lrTemp;
}

BOOL TestSelectedItem(LPVLBOX lpVLBox, VLBSTRUCT vlbStruct) {
    if ( lpVLBox->wFlags & USEDATAVALUES ) {
       if ( lpVLBox->lSelItem == vlbStruct.lData )
         return TRUE;
       else
         return FALSE;
    }
    else {
       if ( lpVLBox->lSelItem == vlbStruct.lIndex )
         return TRUE;
       else
         return FALSE;
    }
}

void SetSelectedItem(LPVLBOX lpVLBox) {
    int nSelected;
    nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
    if ( nSelected == LB_ERR )
       return;

    if ( lpVLBox->wFlags & USEDATAVALUES ) {
       lpVLBox->lSelItem =
            SendMessage(lpVLBox->hwndList, LB_GETITEMDATA, nSelected, 0L);
    }
    else {
       lpVLBox->lSelItem = (LONG)nSelected + lpVLBox->lToplIndex;
    }
}

void vlbLineDn(LPVLBOX lpVLBox) {

   // Do we have a selected item ???
   if ( lpVLBox->lSelItem != -1L ) {
      long lSelected = SendMessage(lpVLBox->hwndList, LB_GETCURSEL,0, 0L);
      if (lSelected == -1L ) {
         // Current selction is visible....NOT
         vlbRedrawOff(lpVLBox);
         // Put selected item at top of LB
         VLBFindPage(lpVLBox, lpVLBox->lSelItem, TRUE);

         // Scroll the LB down a line
         VLBScrollDownLine(lpVLBox);
         SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
         SetFocus(lpVLBox->hwndList);
         SetSelectedItem(lpVLBox);
         // Update the Screen
         vlbRedrawOn(lpVLBox);
      } else {
         // Current selection is visible - Where is it ????
         if ( (int)lSelected == (lpVLBox->nLines-1) ) {
            // At the Bottom... Scroll down 1 page less 1 line
            //                  Put selection at bottom
            VLBScrollDownLine(lpVLBox);
            SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                        lpVLBox->nLines-1, 0L);
            SetFocus(lpVLBox->hwndList);
            SetSelectedItem(lpVLBox);
         }
         else {
            SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                        (int)(lSelected)+1, 0L);
            SetFocus(lpVLBox->hwndList);
            SetSelectedItem(lpVLBox);
         }
      }
   }
}

void vlbLineUp(LPVLBOX lpVLBox) {
    //
    // Do we have a selected item ???
    //
    if (lpVLBox->lSelItem != -1L) {
        long lSelected;
        if ( (lSelected = SendMessage(lpVLBox->hwndList, LB_GETCURSEL,
             0, 0L)) == -1L ) {
               //
               // Current selction is visible....NOT
               //
               vlbRedrawOff(lpVLBox);

               //
               // Put selected item at top of LB
               //
               VLBFindPage(lpVLBox, lpVLBox->lSelItem, TRUE);

               //
               // Scroll the LB down a line
               //
               VLBScrollUpLine(lpVLBox);
               SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
               SetFocus(lpVLBox->hwndList);
               SetSelectedItem(lpVLBox);

               //
               // Update the Screen
               //
               vlbRedrawOn(lpVLBox);
        }
        else {
               //
               // Current selection is visible
               //

               //
               // Where is it ????
               //
               if ( (int)lSelected == 0 ) {
                  //
                  // At the Bottom... Scroll up 1 page less 1 line
                  //                  Put selection at bottom
                  //
                  VLBScrollUpLine(lpVLBox);
                  SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                  SetFocus(lpVLBox->hwndList);
                  SetSelectedItem(lpVLBox);
               }
               else {
                   SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                               (int)(lSelected)-1, 0L);
                   SetFocus(lpVLBox->hwndList);
                   SetSelectedItem(lpVLBox);
               }
        }
    }
}


void vlbPGDN(LPVLBOX lpVLBox) {
    //
    // Do we have a selected item ???
    //
    if ( lpVLBox->lSelItem != -1L )
    {
        long lSelected;
        if ( (lSelected = SendMessage(lpVLBox->hwndList, LB_GETCURSEL,
             0, 0L)) == -1L ) {
               //
               // Current selction is visible....NOT
               //
               vlbRedrawOff(lpVLBox);

               //
               // Put selected item at top of LB
               //
               VLBFindPage(lpVLBox, lpVLBox->lSelItem, TRUE);

               //
               // Scroll the LB down a page
               //
               VLBScrollDownPage(lpVLBox, -1);
               SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
               SetFocus(lpVLBox->hwndList);
               SetSelectedItem(lpVLBox);

               //
               // Update the Screen
               //
               vlbRedrawOn(lpVLBox);
        }
        else {
               //
               // Current selection is visible
               //

               //
               // Where is it ????
               //
               if ( lSelected == 0L ) {
                  //
                  // At the top... put selection at bottom
                  //
                  SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                              lpVLBox->nLines-1, 0L);
                  SetFocus(lpVLBox->hwndList);
                  SetSelectedItem(lpVLBox);
               }
               else if ( (int)lSelected == (lpVLBox->nLines-1) ) {
                  //
                  // At the Bottom... Scroll down 1 page less 1 line
                  //                  Put selection at bottom
                  //
                  VLBScrollDownPage(lpVLBox, -1);
                  SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                              lpVLBox->nLines-1, 0L);
                  SetFocus(lpVLBox->hwndList);
                  SetSelectedItem(lpVLBox);
               }
               else {
                   //
                   // In the middle ... scroll down 1 page less
                   //                   the number of lines
                   //                   the selection is away
                   //                   from the bottom
                   //
                   //                   Put selection at bottom
                   //
                   int nAdjust;
                   nAdjust = -1 * (lpVLBox->nLines-(int)lSelected);
                   VLBScrollDownPage(lpVLBox, nAdjust);
                   SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                               lpVLBox->nLines-1, 0L);
                   SetFocus(lpVLBox->hwndList);
                   SetSelectedItem(lpVLBox);
               }
        }
    }
}


void vlbPGUP(LPVLBOX lpVLBox) {
    //
    // Do we have a selected item ???
    //
    if ( lpVLBox->lSelItem != -1L ) {
        long lSelected;
        if ( (lSelected = SendMessage(lpVLBox->hwndList, LB_GETCURSEL,
             0, 0L)) == -1L ) {
               //
               // Current selction is visible....NOT
               //
               vlbRedrawOff(lpVLBox);

               //
               // Put selected item at top of LB
               //
               VLBFindPage(lpVLBox, lpVLBox->lSelItem, TRUE);

               //
               // Scroll the LB UP a page less 1 line
               //
               VLBScrollUpPage(lpVLBox, -1);
               SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
               SetFocus(lpVLBox->hwndList);
               SetSelectedItem(lpVLBox);

               //
               // Update the Screen
               //
               vlbRedrawOn(lpVLBox);
        }
        else {
               //
               // Current selction is visible
               //

               //
               // Where is it ????
               //
               if ( lSelected == (lpVLBox->nLines-1) ) {
                  //
                  // At the bottom... put selection at top
                  //
                  SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                              0, 0L);
                  SetFocus(lpVLBox->hwndList);
                  SetSelectedItem(lpVLBox);
               }
               else if ( (int)lSelected ==  0L) {
                  //
                  // At the TOP ... Scroll up 1 page less 1 line
                  //                  Put selection at top
                  //
                  VLBScrollUpPage(lpVLBox, -1);
                  SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                              0, 0L);
                  SetFocus(lpVLBox->hwndList);
                  SetSelectedItem(lpVLBox);
               }
               else {
                   //
                   // In the middle ... scroll up 1 page less
                   //                   the number of lines
                   //                   the selection is away
                   //                   from the top
                   //
                   //                   Put selection at top
                   //
                   int nAdjust;
                   nAdjust = -1 * ((int)lSelected + 1 );
                   VLBScrollUpPage(lpVLBox, nAdjust);
                   SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                               0, 0L);
                   SetFocus(lpVLBox->hwndList);
                   SetSelectedItem(lpVLBox);
               }
        }
    }
}

LONG vlbSetCurSel(LONG nOption, LONG lParam, LPVLBOX lpVLBox) {
   int i;
   if ( lpVLBox->wFlags & USEDATAVALUES ) {
       switch ( nOption) {
          case VLB_FIRST:
              VLBFirstPage(lpVLBox);
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
              SetSelectedItem(lpVLBox);
          break;

          case VLB_PREV:
             if ( (i=vlbFindData(lpVLBox, lParam)) == LB_ERR ) {
                if  ( VLBFindPage(lpVLBox, (LONG)lParam, TRUE) ) {
                    return VLB_ERR;
                }
                if ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
                   VLBLastPage(lpVLBox);
                }
                else {
                    InvalidateRect(lpVLBox->hwndList, NULL, TRUE);
                    UpdateWindow(lpVLBox->hwndList);
                }
             }
             i=vlbFindData(lpVLBox, lParam);
             if ( i == 0 ) {
                if ( VLBScrollUpLine(lpVLBox) )
                    return VLB_ERR;
                else
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                    SetSelectedItem(lpVLBox);
             }
             else {
                SendMessage(lpVLBox->hwndList, LB_SETCURSEL, i-1, 0L);
                SetSelectedItem(lpVLBox);
             }
          break;

          case VLB_NEXT:
             if ( (i=vlbFindData(lpVLBox, lParam)) == LB_ERR ) {
                if  ( VLBFindPage(lpVLBox, (LONG)lParam, TRUE) ) {
                    return VLB_ERR;
                }
                UpdateWindow(lpVLBox->hwndList);
                i=vlbFindData(lpVLBox, lParam);
             }
             if ( i == (lpVLBox->nCountInBox-1) ) {
                if ( VLBScrollDownLine(lpVLBox) )
                    return VLB_ERR;
                else
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                lpVLBox->nCountInBox-1, 0L);
                    SetSelectedItem(lpVLBox);
             }
             else {
                if ( SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                 i+1, 0L) == -1L )
                    return VLB_ERR;
                SetSelectedItem(lpVLBox);
             }
          break;

          case VLB_LAST:
              VLBLastPage(lpVLBox);
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                          lpVLBox->nCountInBox-1, 0L);
              SetSelectedItem(lpVLBox);
          break;

          case VLB_FINDITEM:
             if ( (i=vlbFindData(lpVLBox, lParam)) == LB_ERR ) {
                vlbRedrawOff(lpVLBox);
                if  ( VLBFindPage(lpVLBox, (LONG)lParam, TRUE) )
                    return VLB_ERR;
                else {
                    if ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
                       VLBLastPage(lpVLBox);
                    }
                    i=vlbFindData(lpVLBox, lParam);
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, i, 0L);
                    lpVLBox->lSelItem = (LONG) lParam;
                }
                vlbRedrawOn(lpVLBox);
             }
             else {
                SendMessage(lpVLBox->hwndList, LB_SETCURSEL, i, 0L);
                SetSelectedItem(lpVLBox);
             }
          break;
       }
   }
   else {
       lpVLBox->vlbStruct.lIndex = lParam;
       switch ( nOption) {
          case VLB_FIRST:
              VLBFirstPage(lpVLBox);
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
              SetSelectedItem(lpVLBox);
          break;

          case VLB_LAST:
              VLBLastPage(lpVLBox);
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                          lpVLBox->nCountInBox-1, 0L);
              SetSelectedItem(lpVLBox);
          break;

          case VLB_PREV:
             if ( lpVLBox->vlbStruct.lIndex > lpVLBox->lToplIndex &&
                  lpVLBox->vlbStruct.lIndex <= (lpVLBox->lToplIndex +
                                            (LONG)(lpVLBox->nCountInBox)-1)) {
                if ( SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                 (int)(lpVLBox->vlbStruct.lIndex -
                                       lpVLBox->lToplIndex)-1, 0L) == -1L)
                    return VLB_ERR;
                else
                    SetSelectedItem(lpVLBox);
             }
             else {
                if ( VLBScrollUpLine(lpVLBox) )
                    return VLB_ERR;
                else {
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                    SetSelectedItem(lpVLBox);
                }
             }
          break;

          case VLB_NEXT:
             if ( lpVLBox->vlbStruct.lIndex >= lpVLBox->lToplIndex &&
                  lpVLBox->vlbStruct.lIndex < (lpVLBox->lToplIndex +
                                           (LONG)(lpVLBox->nCountInBox)-1)) {
                if ( SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                 (int)(lpVLBox->vlbStruct.lIndex -
                                       lpVLBox->lToplIndex)+1, 0L) == -1L )
                    return VLB_ERR;
                else
                    SetSelectedItem(lpVLBox);
             }
             else {
                if ( VLBScrollDownLine(lpVLBox) )
                    return VLB_ERR;
                else {
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                                lpVLBox->nLines-1, 0L);
                    SetSelectedItem(lpVLBox);
                }
             }
          break;

          case VLB_FINDITEM:
             if ( lpVLBox->vlbStruct.lIndex >= lpVLBox->lToplIndex &&
                  lpVLBox->vlbStruct.lIndex <= (lpVLBox->lToplIndex +
                                            (LONG)(lpVLBox->nCountInBox)-1)) {
                SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                            (int)(lpVLBox->vlbStruct.lIndex -
                                  lpVLBox->lToplIndex), lParam);
                SetSelectedItem(lpVLBox);
             }
             else {
                if ( VLBFindPage(lpVLBox, lpVLBox->vlbStruct.lIndex, TRUE) )
                    return VLB_ERR;
                else {
                    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                    SetSelectedItem(lpVLBox);
                }
             }
          break;
       }
   }
   return (LONG)VLB_OK;
}

LONG VLBNcCreateHandler( HWND hwnd, LPCREATESTRUCT lpcreateStruct) {
  LPSTR lpSpace;
  LPVLBOX lpVLBox;
  HANDLE hVLBox;

  //
  // Allocate storage for the vlbox structure
  //
  if ((hVLBox = GlobalAlloc(GHND, sizeof(VLBOX))) == NULL) {
     return ((long)NULL);
  }
  if ((lpSpace = (LPSTR)GlobalLock(hVLBox)) == NULL) {
     GlobalFree(hVLBox);
     return ((long)NULL);
  }
  lpVLBox = (LPVLBOX) lpSpace;

  if (!lpVLBox)
      // Error, no memory
      return((long)NULL);

#ifdef WIN32
  SetWindowLong(hwnd, 0, (WPARAM)lpVLBox);
#else
  SetWindowLong(hwnd, 0, (LPARAM)lpVLBox);
#endif

  lpVLBox->styleSave = lpcreateStruct->style;

  //
  // Make sure that there are no scroll bar styles
  //
  SetWindowLong(hwnd, GWL_STYLE,
                (LPARAM)(DWORD)( lpVLBox->styleSave &
                ~WS_VSCROLL & ~WS_HSCROLL));
  Draw3dRegister();
  return((LONG)hwnd);
}


LONG VLBCreateHandler(LPVLBOX lpVLBox, HWND hwnd,
                      LPCREATESTRUCT lpcreateStruct) {
  LONG           windowStyle = lpVLBox->styleSave;
  RECT           rc;
  TEXTMETRIC     TextMetric;
  HDC            hdc;

  //
  // Initialize Variables
  //
  lpVLBox->hwnd            = hwnd;
  lpVLBox->hwndParent      = lpcreateStruct->hwndParent;
  lpVLBox->nId             = (int) lpcreateStruct->hMenu;
  lpVLBox->hInstance       = lpcreateStruct->hInstance;
  lpVLBox->nvlbRedrawState = 1;
  lpVLBox->lNumLogicalRecs = -2L;
  lpVLBox->lSelItem        = -1L;
  lpVLBox->wFlags          = 0;
  lpVLBox->hwndList        = NULL;

  //
  // Check for USEDATAVALUES
  //
  if ( windowStyle & VLBS_USEDATAVALUES )
      lpVLBox->wFlags  |= USEDATAVALUES;
  else
      lpVLBox->wFlags &= ~USEDATAVALUES;

  //
  // Dertermine if this VLB is storing string
  //
  lpVLBox->wFlags |= HASSTRINGS;
  if ((windowStyle & VLBS_OWNERDRAWFIXED )
     && (!(windowStyle & VLBS_HASSTRINGS)))
     lpVLBox->wFlags &= ~HASSTRINGS;

  //
  // Get the font height and Number of lines
  //
  hdc = GetDC(hwnd);
  GetTextMetrics(hdc, &TextMetric);
  ReleaseDC(hwnd,hdc);
  lpVLBox->nchHeight = TextMetric.tmHeight;
  GetClientRect(hwnd,&rc);
  lpVLBox->nLines = ((rc.bottom - rc.top) / lpVLBox->nchHeight);

  //
  // Remove borders and scroll bars, add keyboard input
  //
  windowStyle = windowStyle & ~WS_BORDER & ~WS_THICKFRAME;
  windowStyle = windowStyle & ~WS_VSCROLL & ~WS_HSCROLL;

  //
  // Remove regular list box we don't support
  //
  windowStyle = windowStyle & ~LBS_SORT;
  windowStyle = windowStyle & ~LBS_MULTIPLESEL;
  windowStyle = windowStyle & ~LBS_OWNERDRAWVARIABLE;
  windowStyle = windowStyle & ~LBS_MULTICOLUMN;
  windowStyle = windowStyle & ~VLBS_USEDATAVALUES;

  //
  // Add List box styles we have to have
  //
  windowStyle = windowStyle | LBS_WANTKEYBOARDINPUT;
  windowStyle = windowStyle | LBS_NOINTEGRALHEIGHT;
  windowStyle = windowStyle | LBS_NOTIFY;

  //
  // create the list box window
  //
  lpVLBox->hwndList =
    CreateWindowEx((DWORD)0L,
                 (LPSTR)"LISTBOX",(LPSTR)NULL,
                 windowStyle | WS_CHILD,
                 0,
                 0,
                 rc.right,
                 rc.bottom,
                 lpVLBox->hwnd,
                 (HMENU)VLBLBOXID,
                 lpVLBox->hInstance,
                 NULL);

  if (!lpVLBox->hwndList)
      return((LONG)-1L);

  if ( lpVLBox->styleSave & VLBS_DISABLENOSCROLL ) {
     ShowScrollBar(lpVLBox->hwndList, SB_VERT, TRUE);
     EnableScrollBar(lpVLBox->hwndList, SB_VERT, ESB_DISABLE_BOTH);
     if ( lpVLBox->styleSave & WS_HSCROLL) {
        lpVLBox->bHScrollBar = TRUE;
        ShowScrollBar(lpVLBox->hwndList, SB_HORZ, TRUE);
        EnableScrollBar(lpVLBox->hwndList, SB_HORZ, ESB_DISABLE_BOTH);
        VLBCountLines(lpVLBox);
     }
  }
  else {
     lpVLBox->bHScrollBar = FALSE;
  }

  //
  // Subclass the list box
  //
  lpVLBox->lpfnLBWndProc = (WNDPROC)SetWindowLong(lpVLBox->hwndList,
                                   GWL_WNDPROC,(LONG)(WNDPROC)LBSubclassProc);
  return((LONG)hwnd);
}

void VLBNcDestroyHandler(HWND hwnd,  LPVLBOX lpVLBox,
                         WPARAM wParam, LPARAM lParam) {
  HANDLE lpH;

  if (lpVLBox) {
     // GlobalFreePtr(lpVLBox);
     lpH = GlobalPtrHandle(lpVLBox);
     GlobalUnlock(lpH);
     GlobalFree(lpH);
  }     
  Draw3dUnregister();
    
  //
  // In case rogue messages float through after we have freed the lpVLBox, set
  // the handle in the window structure to FFFF and test for this value at the
  // top of the WndProc
  //
#ifdef WIN32
  SetWindowLong(hwnd, 0, (WPARAM)-1);
#else
  SetWindowLong(hwnd, 0, (LPARAM)-1);
#endif

  DefWindowProc(hwnd, WM_NCDESTROY, wParam, lParam);
}


void VLBSetFontHandler( LPVLBOX lpVLBox, HANDLE hFont, BOOL fRedraw) {
  lpVLBox->hFont = hFont;

#ifdef WIN32
  SendMessage(lpVLBox->hwndList, WM_SETFONT, (WPARAM)hFont, (LPARAM)MAKELPARAM(FALSE,0));
#else
  SendMessage(lpVLBox->hwndList, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
#endif

  VLBSizeHandler(lpVLBox, 0);

  if (fRedraw) {
      InvalidateRect(lpVLBox->hwnd, NULL, TRUE);
  }
}


void VLBSizeHandler( LPVLBOX lpVLBox, int nItemHeight) {
//
// Recalculates the sizes of the internal control in response to a
// resizing of the Virtual List Box window.
//
  HDC             hdc;
  TEXTMETRIC      TextMetric;
  RECT            rcWindow;
  RECT            rcClient;
  HANDLE          hOldFont;

  //
  // Set the line height
  //
  if ( nItemHeight ) {
    lpVLBox->nchHeight = nItemHeight;
  }
  else if ((lpVLBox->styleSave & VLBS_OWNERDRAWFIXED) ) {
    lpVLBox->nchHeight = (int) SendMessage(lpVLBox->hwndList,
                                           LB_GETITEMHEIGHT, 0,0L);
  }
  else {
    hdc = GetDC(lpVLBox->hwndList);
    if (lpVLBox->hFont)
       hOldFont = SelectObject(hdc, lpVLBox->hFont);
    GetTextMetrics(hdc, &TextMetric);
    lpVLBox->nchHeight = TextMetric.tmHeight;
    if (lpVLBox->hFont)
       SelectObject(hdc, hOldFont);
    ReleaseDC(lpVLBox->hwndList,hdc);
  }

  //
  // Get the main windows client area
  //
  GetClientRect(lpVLBox->hwnd,&rcClient);

  //
  // If there is a Window and
  // If the list box is integral height ...
  //
  if ( lpVLBox->hwnd && !(lpVLBox->styleSave & VLBS_NOINTEGRALHEIGHT) ) {
      //
      // Does it need adjusting ??????
      //
      if (rcClient.bottom % lpVLBox->nchHeight) {
          //
          // Adjust
          //
             GetWindowRect(lpVLBox->hwnd,&rcWindow);
             SetWindowPos(lpVLBox->hwnd, NULL, 0, 0,
                 rcWindow.right - rcWindow.left,
                 ((rcClient.bottom / lpVLBox->nchHeight) * lpVLBox->nchHeight)
                     + ((rcWindow.bottom-rcWindow.top) - (rcClient.bottom)),
                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
      }
  }

  //
  // Now adjust the child list box to fill the new main window's
  // client area.
  //
  if ( lpVLBox->hwndList ) {
      //
      // Get the main windows client area
      //
      GetClientRect(lpVLBox->hwnd,&rcClient);
      SetWindowPos(lpVLBox->hwndList, NULL, 0, 0,
         rcClient.right+(GetSystemMetrics(SM_CXBORDER)*2),
         rcClient.bottom+(GetSystemMetrics(SM_CXBORDER)*2),
         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  }
  VLBCountLines( lpVLBox);
}



void VLBCountLines( LPVLBOX lpVLBox) {
  RECT   rcClient;
  LONG   lFreeItem;

  //
  // calculate the number of lines
  //
  GetClientRect(lpVLBox->hwndList,&rcClient);
  lpVLBox->nLines = rcClient.bottom / lpVLBox->nchHeight;

  //
  // If there is stuff already int the list box
  // update the display ( more items or fewer items now )
  //
  if ( lpVLBox->lNumLogicalRecs != -2L ) {
      int nItemsinLB;
      nItemsinLB = SendMessage(lpVLBox->hwndList, LB_GETCOUNT, 0, 0L);
      if ( nItemsinLB > lpVLBox->nLines ) {
         // Free the items you can see.
         vlbRedrawOff(lpVLBox);
         while ( nItemsinLB > lpVLBox->nLines ) {
             nItemsinLB--;
             if ( lpVLBox->wFlags & USEDATAVALUES ) {
                 lFreeItem = SendMessage(lpVLBox->hwndList,
                                         LB_GETITEMDATA, nItemsinLB, 0L);
             }
             else {
                 lFreeItem = lpVLBox->lToplIndex+nItemsinLB;
             }
             SendMessage(lpVLBox->hwndParent, VLBN_FREEITEM,
                         lpVLBox->nId, lFreeItem);
             SendMessage(lpVLBox->hwndList, LB_DELETESTRING, nItemsinLB, 0L);
         }
         UpdateVLBWindow(lpVLBox, NULL);
         vlbRedrawOn(lpVLBox);
      }
      else if ( nItemsinLB < lpVLBox->nLines) {
         // Add items to fill box.
         //
         // Special case. LB can hold all the items. Jump to top.
         if ( lpVLBox->lNumLogicalRecs <= lpVLBox->nLines ) {
            VLBFirstPage(lpVLBox);
         }
         else if ( lpVLBox->wFlags & USEDATAVALUES ) {
             VLBFindPage(lpVLBox, SendMessage(lpVLBox->hwndList,
                                              LB_GETITEMDATA, 0, 0L), FALSE );
         }
         else {
             VLBFindPage(lpVLBox, lpVLBox->lToplIndex, FALSE);
         }
     }
  }
}


static void SetFocustoLB(LPVLBOX lpVLBox);
static void SetFocustoVLB(LPVLBOX lpVLBox);

int VLBScrollDownLine( LPVLBOX lpVLBox) {
    RECT   UpdRect;
    int    nSelected;
    LONG   lFreeItem;

    if ( lpVLBox->wFlags & USEDATAVALUES ) {
        lpVLBox->vlbStruct.lIndex = -1L;
        lFreeItem = SendMessage(lpVLBox->hwndList, LB_GETITEMDATA, 0, 0L);
    }
    else {
        lpVLBox->vlbStruct.lIndex = lpVLBox->lToplIndex + lpVLBox->nLines - 1L;
        lFreeItem = lpVLBox->lToplIndex;
    }

    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lData = SendMessage(lpVLBox->hwndList,
                                           LB_GETITEMDATA,
                                           lpVLBox->nCountInBox-1, 0L);
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_NEXT,
                0, (LPARAM)((LPVLBSTRUCT)&(lpVLBox->vlbStruct)));
    if ( lpVLBox->vlbStruct.nStatus == VLB_OK ) {
       nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
       if ( nSelected == 0 ) {
           SendMessage(lpVLBox->hwndList,
                       LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);
           SetFocustoVLB(lpVLBox);
       }

       //
       // Remove the top String
       //
       SendMessage(lpVLBox->hwndList, LB_DELETESTRING, 0, 0L);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEITEM,
                   lpVLBox->nId, lFreeItem);

       //
       // Add the new line
       //
       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA,
                       lpVLBox->nCountInBox-1, lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);
       lpVLBox->lToplIndex++;
       UpdateVLBWindow(lpVLBox, &UpdRect);

       //
       // Tell Windows not to paint the whole LB
       //
       ValidateRect(lpVLBox->hwndList, NULL);

       //
       // Scroll the window up
       //
       ScrollWindow(lpVLBox->hwndList, 0, (-1)*lpVLBox->nchHeight, NULL, NULL);

       //
       // Now tell windows the bottom line needs fixing
       //
       SendMessage(lpVLBox->hwndList, LB_GETITEMRECT,
                   lpVLBox->nLines-1, (LPARAM) (LPRECT) &UpdRect);
       InvalidateRect(lpVLBox->hwndList, &UpdRect, TRUE);
       UpdateWindow(lpVLBox->hwndList);
       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, lpVLBox->nLines-1, 0L);
          SetFocustoLB(lpVLBox);
       }
       else if ( nSelected != LB_ERR ) {
          if ( nSelected != 0 ) {
              // Need to move the selection Up 1
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL, nSelected-1, 0L);
          }
       }
       return VLB_OK;
    }
    return VLB_ERR;
}

int VLBScrollUpLine( LPVLBOX lpVLBox) {
    RECT   UpdRect;
    RECT   ListRect;
    RECT   FAR *lpRect;
    int    nSelected;
    LONG   lFreeItem;

    if ( lpVLBox->wFlags & USEDATAVALUES ) {
        lpVLBox->vlbStruct.lIndex = -1L;
        lFreeItem = SendMessage(lpVLBox->hwndList, LB_GETITEMDATA,
                                lpVLBox->nCountInBox-1, 0L);
    }
    else {
        lpVLBox->vlbStruct.lIndex = lpVLBox->lToplIndex;
        lFreeItem = lpVLBox->lToplIndex + lpVLBox->nLines - 1L;
    }

    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lData = SendMessage(lpVLBox->hwndList,
                                           LB_GETITEMDATA, 0, 0L);
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_PREV, 0,
                (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
    if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
       nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
       if ( nSelected == lpVLBox->nLines-1 ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);
          SetFocustoVLB(lpVLBox);
       }

       //
       // Remove the bottom String
       //
       SendMessage(lpVLBox->hwndList, LB_DELETESTRING, lpVLBox->nLines-1, 0L);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEITEM,
                   lpVLBox->nId, lFreeItem);

       //
       // Add the new line
       //
       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                       lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);

       lpVLBox->lToplIndex--;
       UpdateVLBWindow(lpVLBox, &UpdRect);

       //
       // Tell Windows not to paint the whole LB
       //
       ValidateRect(lpVLBox->hwndList, NULL);

       //
       // Check for partial line at bottom...
       // if so clear it
       //
       SendMessage(lpVLBox->hwndList, LB_GETITEMRECT,
                   lpVLBox->nLines-1, (LPARAM)(LPRECT)&UpdRect);

       GetClientRect(lpVLBox->hwndList, &ListRect);
       if ( lpVLBox->bHScrollBar || (UpdRect.bottom != ListRect.bottom) ) {
           ListRect.bottom = UpdRect.top ;
           lpRect = &ListRect;
       }
       else {
           lpRect = NULL;
       }

       //
       // Scroll the window down
       //
       ScrollWindow(lpVLBox->hwndList, 0, lpVLBox->nchHeight, lpRect, NULL);

       //
       // Now tell windows the top line needs fixing
       //
       SendMessage(lpVLBox->hwndList, LB_GETITEMRECT,
                   0, (LPARAM)(LPRECT)&UpdRect);
       InvalidateRect(lpVLBox->hwndList, &UpdRect, TRUE);
       UpdateWindow(lpVLBox->hwndList);

       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
          SetFocustoLB(lpVLBox);
       }
       else if ( nSelected != LB_ERR ) {
          if ( nSelected !=  lpVLBox->nLines-1) {
              // Need to move the selection Up 1
              SendMessage(lpVLBox->hwndList, LB_SETCURSEL, nSelected+1, 0L);
          }
       }


       return VLB_OK;
    }
    return VLB_ERR;
}


int VLBScrollDownPage( LPVLBOX lpVLBox, int nAdjustment) {
    int  nCount;
    int  nSelected;
    LONG lFreeItem;

    nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
    if ( nSelected == LB_ERR )
        nSelected = -10000;

    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);
    SetFocustoVLB(lpVLBox);

    for ( nCount = 0; nCount < lpVLBox->nLines+nAdjustment; nCount++) {
        if ( lpVLBox->wFlags & USEDATAVALUES )
            lpVLBox->vlbStruct.lIndex = -1L;
        else
            lpVLBox->vlbStruct.lIndex = lpVLBox->lToplIndex +
                                        lpVLBox->nLines - 1L;

        lpVLBox->vlbStruct.lpTextPointer = NULL;
        lpVLBox->vlbStruct.lData = SendMessage(lpVLBox->hwndList,
                                               LB_GETITEMDATA,
                                               lpVLBox->nCountInBox-1, 0L);
        lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
        SendMessage(lpVLBox->hwndParent, VLB_NEXT, 0,
                    (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
        if (  lpVLBox->vlbStruct.nStatus == VLB_OK ) {

           if ( nCount == 0 )
              vlbRedrawOff(lpVLBox);

           if ( lpVLBox->wFlags & USEDATAVALUES ) {
               lFreeItem = SendMessage(lpVLBox->hwndList,
                                       LB_GETITEMDATA, 0, 0L);
           }
           else {
               lFreeItem = lpVLBox->lToplIndex;
           }
           SendMessage(lpVLBox->hwndList, LB_DELETESTRING, 0, 0L);
           SendMessage(lpVLBox->hwndParent, VLBN_FREEITEM,
                       lpVLBox->nId, lFreeItem);

           if ( lpVLBox->wFlags & HASSTRINGS) {
               SendMessage(lpVLBox->hwndList, LB_ADDSTRING,
                           0, (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
               SendMessage(lpVLBox->hwndList, LB_SETITEMDATA,
                           lpVLBox->nCountInBox-1, lpVLBox->vlbStruct.lData);
           }
           else
               SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                           (LPARAM) lpVLBox->vlbStruct.lData);

           if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
              nSelected = lpVLBox->nLines-1;
           }
           else {
              nSelected--;
           }

           lpVLBox->lToplIndex++;

        }
        else {
            if ( nCount == 0 )
                return VLB_ERR;
            break;
        }
    }

    if ( nSelected >= 0 ) {
       SendMessage(lpVLBox->hwndList, LB_SETCURSEL, nSelected, 0L);
       SetFocustoLB(lpVLBox);
    }
    else {
       SetFocustoVLB(lpVLBox);
       SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);
    }

    UpdateVLBWindow(lpVLBox, NULL);
    vlbRedrawOn(lpVLBox);
    return VLB_OK;

}


int VLBScrollUpPage( LPVLBOX lpVLBox, int nAdjustment) {
    int  nCount;
    int  nSelected;
    LONG lFreeItem;

    nSelected = (int)SendMessage(lpVLBox->hwndList, LB_GETCURSEL, 0, 0L);
    if ( nSelected == LB_ERR )
        nSelected = -10000;

    SetFocustoVLB(lpVLBox);
    SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);

    for ( nCount = 0; nCount < lpVLBox->nLines+nAdjustment; nCount++) {
        if ( lpVLBox->wFlags & USEDATAVALUES ) {
            lpVLBox->vlbStruct.lIndex = -1L;
        }
        else {
            lpVLBox->vlbStruct.lIndex = lpVLBox->lToplIndex;
        }

        lpVLBox->vlbStruct.lpTextPointer = NULL;
        lpVLBox->vlbStruct.lData = SendMessage(lpVLBox->hwndList,
                                               LB_GETITEMDATA, 0, 0L);
        lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
        SendMessage(lpVLBox->hwndParent, VLB_PREV, 0,
                    (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
        if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
           if ( nCount == 0 )
              vlbRedrawOff(lpVLBox);

           if ( lpVLBox->wFlags & HASSTRINGS) {
               SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                           (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
               SendMessage(lpVLBox->hwndList,
                           LB_SETITEMDATA, 0, lpVLBox->vlbStruct.lData);
           }
           else
               SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                           (LPARAM) lpVLBox->vlbStruct.lData);

           if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
              nSelected = 0;
           }
           else {
              nSelected++;
           }

           if ( lpVLBox->wFlags & USEDATAVALUES ) {
               lFreeItem = SendMessage(lpVLBox->hwndList, LB_GETITEMDATA,
                                       lpVLBox->nLines, 0L);
           }
           else {
               lFreeItem = lpVLBox->lToplIndex + lpVLBox->nLines - 1L;
           }
           SendMessage(lpVLBox->hwndList, LB_DELETESTRING,
                       lpVLBox->nLines, 0L);
           SendMessage(lpVLBox->hwndParent, VLBN_FREEITEM,
                       lpVLBox->nId, lFreeItem);
           lpVLBox->lToplIndex--;
        }
        else  {
            if ( nCount == 0 )
               return VLB_ERR;
           break;
        }
    }

    if ( nSelected >= 0 && nSelected <= lpVLBox->nLines ) {
       SendMessage(lpVLBox->hwndList, LB_SETCURSEL, nSelected, 0L);
       SetFocustoLB(lpVLBox);
    }
    else {
       SetFocustoVLB(lpVLBox);
       SendMessage(lpVLBox->hwndList, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0L);
    }
    UpdateVLBWindow(lpVLBox, NULL);
    vlbRedrawOn(lpVLBox);
    return VLB_OK;
}


void UpdateVLBWindow( LPVLBOX lpVLBox, LPRECT lpRect) {
    int   nPos;
    if ( lpVLBox->lNumLogicalRecs == -1L )
       SetScrollPos(lpVLBox->hwndList, SB_VERT, 50, TRUE);
    else {
       if ( lpVLBox->lNumLogicalRecs <= lpVLBox->nLines ) {
          if ( lpVLBox->styleSave & VLBS_DISABLENOSCROLL )
             EnableScrollBar(lpVLBox->hwndList, SB_VERT, ESB_DISABLE_BOTH);
          else
             ShowScrollBar(lpVLBox->hwndList, SB_VERT, FALSE);
       }
       else {
           if ( lpVLBox->styleSave & VLBS_DISABLENOSCROLL )
              EnableScrollBar(lpVLBox->hwndList, SB_VERT, ESB_ENABLE_BOTH);
           else
              ShowScrollBar(lpVLBox->hwndList, SB_VERT, TRUE);
           if ( lpVLBox->lToplIndex >= (lpVLBox->lNumLogicalRecs -
                                        lpVLBox->nLines) ) {
               nPos = 100;
           }
           else if (lpVLBox->lToplIndex == 0L) {
               nPos = 0;
           }
           else {
               nPos = (int) ((lpVLBox->lToplIndex*100L) /
                             (lpVLBox->lNumLogicalRecs-lpVLBox->nLines+1));
           }
           SetScrollPos(lpVLBox->hwndList, SB_VERT, nPos, TRUE);
       }
    }
}



int VLBFindPos( LPVLBOX lpVLBox, int nPos) {
    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lIndex = (LONG) nPos;
    lpVLBox->vlbStruct.lData = (LONG) nPos;
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_FINDPOS, 0, (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
    if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
       SetFocustoVLB(lpVLBox);
       vlbRedrawOff(lpVLBox);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
       SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);

       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                       lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);

       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
          SetFocustoLB(lpVLBox);
       }

       if ( lpVLBox->lNumLogicalRecs == -1L )
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lData;
       else if ( lpVLBox->wFlags & USEDATAVALUES )
          lpVLBox->lToplIndex = (LONG)nPos* (lpVLBox->lNumLogicalRecs -
                                             lpVLBox->nLines+1)/100L;
       else
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lIndex;

       lpVLBox->vlbStruct.lIndex = 0L;
       lpVLBox->nCountInBox = 1;
       while ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
          lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
          SendMessage(lpVLBox->hwndParent, VLB_NEXT, 0,
                      (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
             if ( lpVLBox->wFlags & HASSTRINGS) {
                 SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
                 SendMessage(lpVLBox->hwndList, LB_SETITEMDATA,
                             lpVLBox->nCountInBox, lpVLBox->vlbStruct.lData);
             }
             else
                 SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lData);

             if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
                SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
                SetFocustoLB(lpVLBox);
             }

             lpVLBox->nCountInBox++;
          }
          else
            break;
       }
       UpdateVLBWindow(lpVLBox, NULL);
       vlbRedrawOn(lpVLBox);
       return VLB_OK;
    }
    else
        return VLB_ERR;
}


int VLBFindPage( LPVLBOX lpVLBox, LONG lFindRecNum, BOOL bUpdateTop) {
    int nSelected;

    nSelected = -1000;
    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = lFindRecNum;
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_FINDITEM, 0,
                (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
    if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
       SetFocustoVLB(lpVLBox);
       vlbRedrawOff(lpVLBox);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
       SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);

       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                       lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);
       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
          nSelected = 0;
       }

       if ( bUpdateTop ) {
           if ( lpVLBox->lNumLogicalRecs == -1L )
              lpVLBox->lToplIndex = lpVLBox->vlbStruct.lData;
           else if ( lpVLBox->wFlags & USEDATAVALUES )
              lpVLBox->lToplIndex = lpVLBox->lNumLogicalRecs/2L;
           else
              lpVLBox->lToplIndex = lpVLBox->vlbStruct.lIndex;
       }
       lpVLBox->vlbStruct.lIndex = lFindRecNum;
       lpVLBox->nCountInBox = 1;
       while ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
          lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
          SendMessage(lpVLBox->hwndParent, VLB_NEXT, 0,
                      (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
             if ( lpVLBox->wFlags & HASSTRINGS) {
                 SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
                 SendMessage(lpVLBox->hwndList, LB_SETITEMDATA,
                             lpVLBox->nCountInBox, lpVLBox->vlbStruct.lData);
             }
             else
                 SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lData);
             if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
                 nSelected = lpVLBox->nCountInBox;
             }

             lpVLBox->nCountInBox++;
          }
          else
            break;
       }
       if ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
          if ( lpVLBox->wFlags & USEDATAVALUES )
              lpVLBox->vlbStruct.lIndex = -1L;
          else
              lpVLBox->vlbStruct.lIndex = lpVLBox->lToplIndex;
          lpVLBox->vlbStruct.lpTextPointer = NULL;
          lpVLBox->vlbStruct.lData = SendMessage(lpVLBox->hwndList,
             LB_GETITEMDATA, 0, 0L);
          while ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
             lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
             SendMessage(lpVLBox->hwndParent, VLB_PREV, 0,
                         (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
             if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
                if ( lpVLBox->wFlags & HASSTRINGS) {
                    SendMessage(lpVLBox->hwndList, LB_INSERTSTRING,
                                0, (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
                    SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                                lpVLBox->vlbStruct.lData);
                }
                else
                    SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                                (LPARAM) lpVLBox->vlbStruct.lData);
                if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
                    nSelected = 0;
                }
                else {
                    nSelected++;
                }
                lpVLBox->nCountInBox++;
                if ( lpVLBox->lNumLogicalRecs != -1L )
                   lpVLBox->lToplIndex--;
             }
             else
                break;
          }
       }
       if ( nSelected >= 0 ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, nSelected, 0L);
          SetFocustoLB(lpVLBox);
       }
       UpdateVLBWindow(lpVLBox, NULL);
       vlbRedrawOn(lpVLBox);
       return VLB_OK;
    }
    else
        return VLB_ERR;
}

void VLBFirstPage( LPVLBOX lpVLBox) {
    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = 0L;
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_FIRST, 0,
                (LPARAM)((LPVLBSTRUCT)&(lpVLBox->vlbStruct)));
    if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
       SetFocustoVLB(lpVLBox);
       vlbRedrawOff(lpVLBox);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
       SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);
       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                       lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);

       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
           SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
           SetFocustoLB(lpVLBox);
       }
       if ( lpVLBox->lNumLogicalRecs == -1L )
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lData;
       else if ( lpVLBox->wFlags & USEDATAVALUES )
          lpVLBox->lToplIndex = 0L;
       else
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lIndex;

       lpVLBox->vlbStruct.lIndex = 0L;
       lpVLBox->nCountInBox = 1;
       while ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
          lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
          SendMessage(lpVLBox->hwndParent, VLB_NEXT, 0,
                      (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
            if ( lpVLBox->wFlags & HASSTRINGS) {
                SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                            (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
                SendMessage(lpVLBox->hwndList, LB_SETITEMDATA,
                            lpVLBox->nCountInBox, lpVLBox->vlbStruct.lData);
            }
            else
                SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                            (LPARAM) lpVLBox->vlbStruct.lData);
            if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
               SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                           lpVLBox->nCountInBox, 0L);
               SetFocustoLB(lpVLBox);
            }
            lpVLBox->vlbStruct.lIndex = (LONG) lpVLBox->nCountInBox;
            lpVLBox->nCountInBox++;
          }
          else
            break;
       }
    }
    UpdateVLBWindow(lpVLBox, NULL);
    vlbRedrawOn(lpVLBox);
}

void VLBLastPage(LPVLBOX lpVLBox) {
    lpVLBox->vlbStruct.lpTextPointer = NULL;
    lpVLBox->vlbStruct.lData = lpVLBox->vlbStruct.lIndex = 0L;
    lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
    SendMessage(lpVLBox->hwndParent, VLB_LAST, 0,
                (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
    if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
       SetFocustoVLB(lpVLBox);
       vlbRedrawOff(lpVLBox);
       SendMessage(lpVLBox->hwndParent, VLBN_FREEALL, lpVLBox->nId, 0L);
       SendMessage(lpVLBox->hwndList, LB_RESETCONTENT, 0, 0L);
       if ( lpVLBox->wFlags & HASSTRINGS) {
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
           SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                       lpVLBox->vlbStruct.lData);
       }
       else
           SendMessage(lpVLBox->hwndList, LB_ADDSTRING, 0,
                       (LPARAM) lpVLBox->vlbStruct.lData);
       if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
          SendMessage(lpVLBox->hwndList, LB_SETCURSEL, 0, 0L);
          SetFocustoLB(lpVLBox);
       }
       if ( lpVLBox->lNumLogicalRecs == -1L )
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lData;
       else if ( lpVLBox->wFlags & USEDATAVALUES )
          lpVLBox->lToplIndex = lpVLBox->lNumLogicalRecs;
       else
          lpVLBox->lToplIndex = lpVLBox->vlbStruct.lIndex;

       lpVLBox->nCountInBox = 1;
       while ( lpVLBox->nCountInBox < lpVLBox->nLines ) {
          lpVLBox->vlbStruct.nCtlID = lpVLBox->nId;
          SendMessage(lpVLBox->hwndParent, VLB_PREV, 0,
                      (LPARAM)(LPVLBSTRUCT)&(lpVLBox->vlbStruct));
          if ( lpVLBox->vlbStruct.nStatus  == VLB_OK ) {
             if ( lpVLBox->wFlags & HASSTRINGS) {
                 SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lpTextPointer);
                 SendMessage(lpVLBox->hwndList, LB_SETITEMDATA, 0,
                             lpVLBox->vlbStruct.lData);
             }
             else
                 SendMessage(lpVLBox->hwndList, LB_INSERTSTRING, 0,
                             (LPARAM) lpVLBox->vlbStruct.lData);

             if ( TestSelectedItem(lpVLBox, lpVLBox->vlbStruct) ) {
                 SendMessage(lpVLBox->hwndList, LB_SETCURSEL,
                             lpVLBox->nCountInBox, 0L);
                 SetFocustoLB(lpVLBox);
             }

             lpVLBox->nCountInBox++;
             if ( lpVLBox->lNumLogicalRecs != -1L )
                lpVLBox->lToplIndex--;
          }
          else
             break;
       }
       UpdateVLBWindow(lpVLBox, NULL);
       vlbRedrawOn(lpVLBox);
    }
}


static void SetFocustoLB(LPVLBOX lpVLBox) {
   lpVLBox->wFlags &= ~PARENTFOCUS;
   if ( lpVLBox->wFlags & HASFOCUS ) {
      SetFocus(lpVLBox->hwndList);
   }
}

static void SetFocustoVLB(LPVLBOX lpVLBox) {
   lpVLBox->wFlags |= PARENTFOCUS;
   if ( lpVLBox->wFlags & HASFOCUS ) {
      SetFocus(lpVLBox->hwnd);
   }
}
//
// Sample 3D Drawing routines
//  

#ifdef WIN32
#define _fmemicmp memicmp
#endif

// Windows Versions (Byte order flipped from GetWindowsVersion)
#define ver30 0x0300      

typedef COLORREF CV;
// CoLoR Table
typedef struct {
    CV rgcv[ICVMAX];
} CLRT;

// BRush Table
typedef struct {
    HBRUSH mpicvhbr[ICVBRUSHMAX];
} BRT;

int mpicvSysColor[] = {
    COLOR_BTNHIGHLIGHT,
    COLOR_BTNFACE,
    COLOR_BTNSHADOW,
    COLOR_BTNTEXT,
    COLOR_WINDOW,
    COLOR_WINDOWTEXT,
    COLOR_GRAYTEXT,
    COLOR_WINDOWFRAME
};


static BOOL InternalDraw3dColorChange(BOOL fForce);
static VOID DeleteObjectNull(HANDLE FAR *ph);
static VOID DeleteObjects(VOID);
static VOID PatFill(HDC hdc, RC FAR *lprc);

/*-----------------------------------------------------------------------
|   Draw3d Global ( Static ) Variables
-----------------------------------------------------------------------*/
CLRT clrt;
BRT brt;    
BOOL f3dDialogs;
int cInited;
WORD verWindows;
 
/*-----------------------------------------------------------------------
|   Draw3d Utility routines
-----------------------------------------------------------------------*/
static VOID DeleteObjectNull(HANDLE FAR *ph) {
   if (*ph != NULL) {
      DeleteObject(*ph);
      *ph = NULL;
   }
}

static VOID DeleteObjects(VOID) {
   int icv;
   for (icv = 0; icv < ICVBRUSHMAX; icv++)
      DeleteObjectNull(&brt.mpicvhbr[icv]);
}

static VOID PatFill(HDC hdc, RC FAR *lprc) {
    PatBlt(hdc, lprc->xLeft, lprc->yTop,
           lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
}

       
/*-----------------------------------------------------------------------
|   Draw3dRec
|
|   Arguments:
|       HDC hdc:    
|       RC FAR *lprc:   
|       LONG cvUpperLeft:  
|       LONG cvLowerRight:  
|       WORD grbit;
|       
|   Returns:
|       
-----------------------------------------------------------------------*/
VOID Draw3dRec(HDC hdc, RC FAR *lprc, ICV icvUpperLeft,
               ICV icvLowerRight, DR3 dr3) {
    COLORREF cvSav;
    RC rc;
    cvSav = SetBkColor(hdc, clrt.rgcv[icvUpperLeft]);
    // top
    rc = *lprc;
    rc.yBot = rc.yTop+1;
    if (dr3 & DR3TOP)
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
            (char far *) NULL, 0, (int far *) NULL);
    // left
    rc.yBot = lprc->yBot;
    rc.xRight = rc.xLeft+1;
    if (dr3 & DR3LEFT)
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
            (char far *) NULL, 0, (int far *) NULL);
    if (icvUpperLeft != icvLowerRight)
        SetBkColor(hdc, clrt.rgcv[icvLowerRight]);
    // right
    rc.xRight = lprc->xRight;
    rc.xLeft = rc.xRight-1;
    if (dr3 & DR3RIGHT)
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
            (char far *) NULL, 0, (int far *) NULL);
    // bot
    if (dr3 & DR3BOT) {
        rc.xLeft = lprc->xLeft;
        rc.yTop = rc.yBot-1;
        if (dr3 & DR3HACKBOTRIGHT)
            rc.xRight -=2;
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc, 
            (char far *) NULL, 0, (int far *) NULL);
    }
    SetBkColor(hdc, cvSav);
}

VOID Draw3dInsetRect(HDC hdc, RC FAR *prc, DR3 dr3) {
    RC rc;

    rc = *prc;
    Draw3dRec(hdc, &rc, ICVWINDOWFRAME, ICVBTNFACE, (WORD)(dr3 & DR3ALL));
    rc.xLeft--;
    rc.yTop--;
    rc.xRight++;
    rc.yBot++;
    Draw3dRec(hdc, &rc, ICVBTNSHADOW, ICVBTNHILITE, dr3);
}

/*-----------------------------------------------------------------------
|   Draw3dCtlColor
|
|       Common CTL_COLOR processor for 3d UITF dialogs & alerts.
|
|   Arguments:
|
|   Returns:
|       appropriate brush if f3dDialogs.  Returns FALSE otherwise
|
-----------------------------------------------------------------------*/
HBRUSH FAR PASCAL Draw3dCtlColor(UINT wm, WPARAM wParam, LPARAM lParam) {
   if (f3dDialogs) {
      SetTextColor((HDC) wParam, clrt.rgcv[ICVBTNTEXT]);
      SetBkColor((HDC) wParam, clrt.rgcv[ICVBTNFACE]);
      return brt.mpicvhbr[ICVBTNFACE];
   }
   return (HBRUSH) FALSE;
}

/*-----------------------------------------------------------------------
|   Draw3dColorChange
|   
|       App calls this when it gets a WM_SYSCOLORCHANGE message
|       
|   Returns:
|       TRUE if successful.
|       
-----------------------------------------------------------------------*/
BOOL FAR PASCAL Draw3dColorChange(VOID) {
   return InternalDraw3dColorChange(FALSE);
}

static BOOL InternalDraw3dColorChange(BOOL fForce) {
    ICV icv;
    static CLRT clrtNew;
    static BRT brtNew;

    if (!f3dDialogs)
        return FALSE;

    for (icv = 0; icv < ICVMAX; icv++)
        clrtNew.rgcv[icv] = GetSysColor(mpicvSysColor[icv]);

    if (verWindows == ver30)
        clrtNew.rgcv[ICVBTNHILITE] = RGB(0xff, 0xff, 0xff);

    if (clrtNew.rgcv[ICVGRAYTEXT] == 0L ||
        clrtNew.rgcv[ICVGRAYTEXT] == clrtNew.rgcv[ICVBTNFACE])
       clrtNew.rgcv[ICVGRAYTEXT] = RGB(0x80, 0x80, 0x80);
    if (clrtNew.rgcv[ICVGRAYTEXT] == clrtNew.rgcv[ICVBTNFACE])
       clrtNew.rgcv[ICVGRAYTEXT] = 0L;

    if (fForce || _fmemicmp(&clrt, &clrtNew, sizeof(CLRT))) {
        for (icv = 0; icv < ICVBRUSHMAX; icv++)
            brtNew.mpicvhbr[icv] = CreateSolidBrush(clrtNew.rgcv[icv]);

        for (icv = 0; icv < ICVBRUSHMAX; icv++) {
            if (brtNew.mpicvhbr[icv] == NULL) {
               for (icv = 0; icv < ICVBRUSHMAX; icv++)
                  DeleteObjectNull(&brtNew.mpicvhbr[icv]);
               return FALSE;
            }
        }

        DeleteObjects();
        brt = brtNew;
        clrt = clrtNew;
        return TRUE;
    }       
    return TRUE;
}

#ifdef IN_A_DLL
/*-----------------------------------------------------------------------
|   LibMain
-----------------------------------------------------------------------*/
#ifdef WIN32
BOOL LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
#else
int FAR PASCAL LibMain(hModule, wDataSeg, cbHeapSize, lpszCmdLine)
HANDLE  hModule;
WORD    wDataSeg;
WORD    cbHeapSize;
LPSTR   lpszCmdLine;
#endif
{
   return 1;
}

#endif
  
BOOL FInit3dDialogs(VOID) {
    HDC hdc;
    extern HANDLE hinstLib;
    WORD wT;

    wT = (WORD) GetVersion();
    verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT); 
    
    hdc = GetDC(NULL);
    f3dDialogs = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES) >= 4;
    
    // Win 3.1 EGA lies to us...
    if (GetSystemMetrics(SM_CYSCREEN) == 350 &&
        GetSystemMetrics(SM_CXSCREEN) == 640)
      f3dDialogs = FALSE;
        
    ReleaseDC(NULL, hdc);
    if (f3dDialogs) {
      if ( !InternalDraw3dColorChange(TRUE)) {
         f3dDialogs = FALSE;
      }            
    }
    return f3dDialogs;
}

VOID End3dDialogs(VOID) {
  DeleteObjects();
  f3dDialogs = FALSE;
}
               
               
BOOL FAR PASCAL Draw3dRegister(void) {
    cInited++;  
    if (cInited == 1) {
        return FInit3dDialogs();
    }
    return f3dDialogs;
}


BOOL FAR PASCAL Draw3dUnregister(void) {
    cInited--;
        
    if (cInited == 0) {
       End3dDialogs();
    }
    return TRUE;
}

/************************************* EOF *********************************/
