home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / cprog / vxbc15.zip / VXSAMP.C < prev    next >
C/C++ Source or Header  |  1992-03-07  |  39KB  |  1,086 lines

  1. /*
  2. ┌──────────────────────────────────────────────────────────────────────────┐
  3. │ vxBase xbase for Visual Basic library                                    │
  4. │ Copyright 1992 vxBase (512523 Alberta Ltd.)                              │
  5. ├────────────────┬──────┬────────────┬────────┬───────────────┬────────────┤
  6. │ SYSTEM         │ VX   │ PROGRAM ID │ VXSAMP │ CREATION DATE │  02/29/92  │
  7. ├────────────────┼──────┴────────────┴────────┴───────────────┴────────────┤
  8. │ PROGRAM TITLE  │  sample c program using vxbase functions from vxbase.dll│
  9. ├─────┬──────┬───┴┬───────────────────────────┬────────────────────────────┤
  10. │ REV │ DATE │ BY │ DESCRIPTION               │ Written by T. Orletsky     │
  11. ├─────┼──────┼────┼───────────────────────────┴────────────────────────────┤
  12. │     │      │    │                                                        │
  13. └─────┴──────┴────┴────────────────────────────────────────────────────────┘
  14.  
  15. This sample code and all other supplied sample files should be
  16. loaded into \borlandc\vxbase to use the .def and project files
  17. for compilation under Borland c++ (ver 2.0) from within the ide.
  18.  
  19. */
  20.  
  21. #include <windows.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <dos.h>
  25. #include "vxb.h"
  26. #include "vxsamp.h"
  27.  
  28.  
  29. /* ********************************************************* */
  30. /*                global vars defined                        */
  31. /* ********************************************************* */
  32.  
  33. HWND        hgWnd;               //Global Window Handle. 
  34. HANDLE      hgInst;              //Global Instance Handle. 
  35.  
  36. int         DbfArea1;            //vxbase dbf area 1
  37. int         NtxArea1;            //vxbase ntx area 1
  38. int         DbfArea2;            //vxbase dbf area 2
  39. int         NtxArea2;            //vxbase ntx area 2
  40. long        RetVal;              //vxbrowse return value
  41. char        szBuffer[81];        //miscellaneous buffer
  42. char        szBuffer2[81];       //miscellaneous buffer 2
  43.  
  44. /*
  45.  * Array of pointers to strings loaded from the resource file.
  46.  * Pointers can be near since LocalAlloc will be used to get
  47.  * the string space.
  48.  */
  49.  
  50. char NEAR   *rgpsz[CSTRINGS];
  51.  
  52.  
  53. /*
  54.  * WinMain
  55.  *
  56.  * Purpose:
  57.  *  Main entry point of application.   Should register the app class
  58.  *  if a previous instance has not done so and do any other one-time
  59.  *  initializations.
  60.  *
  61.  * Parameters:
  62.  *  See Windows SDK Guide to Programming, page 2-3
  63.  *
  64.  * Return Value:
  65.  *  Value to return to Windows--termination code.
  66.  *
  67.  */
  68.  
  69. #pragma argsused
  70. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  71.                     LPSTR lpszCmdLine, int nCmdShow)
  72.     {
  73.     WNDCLASS    wndClass;
  74.     HANDLE      hStringMem;
  75.     HWND        hWnd;
  76.     MSG         msg;
  77.  
  78.     hgInst = hInstance;
  79.  
  80.     /*
  81.      * InitApp allocates local memory for strings. WinMain must free.
  82.      * If this fails, we should quit BEFORE any classes are registered
  83.      * or do anything else that uses up USER or GDI resources.
  84.      */
  85.     hStringMem = HLoadAppStrings();
  86.  
  87.     if (hStringMem == NULL)
  88.         {
  89.         LocalFree(hStringMem);
  90.         return FALSE;
  91.         }
  92.  
  93.     if (!hPrevInstance)
  94.         {
  95.         wndClass.style          = CS_HREDRAW | CS_VREDRAW;
  96.         wndClass.lpfnWndProc    = vxWndProc;
  97.         wndClass.cbClsExtra     = 0;
  98.         wndClass.cbWndExtra     = 0;
  99.         wndClass.hInstance      = hInstance;
  100.         wndClass.hIcon          = LoadIcon(hInstance, "vxIcon");
  101.         wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  102.         wndClass.hbrBackground  = COLOR_BTNFACE + 1;
  103.         wndClass.lpszMenuName   = "vxMenu";
  104.         wndClass.lpszClassName  = "vxSamp";
  105.  
  106.         if (!RegisterClass(&wndClass))
  107.             return FALSE;
  108.         }
  109.  
  110.     hWnd = CreateWindow("vxSamp",
  111.                        rgpsz[IDS_CAPTION],
  112.                        WS_MINIMIZEBOX | WS_OVERLAPPEDWINDOW,
  113.                        50, 50, 500, 300,
  114.                        NULL,
  115.                        NULL,
  116.                        hInstance,
  117.                        NULL);
  118.  
  119.     hgWnd = hWnd;
  120.     ShowWindow(hWnd, nCmdShow);
  121.     UpdateWindow(hWnd);
  122.  
  123.  
  124.     while (GetMessage(&msg, NULL, 0, 0))
  125.         {
  126.         TranslateMessage(&msg);
  127.         DispatchMessage(&msg);
  128.         }
  129.  
  130.     LocalFree(hStringMem);
  131.     return msg.wParam;
  132.     }
  133.  
  134. /*
  135.  * vxWndProc
  136.  *
  137.  * Purpose:
  138.  *  Window class procedure.  Standard callback.
  139.  *
  140.  * Parameters:
  141.  *  The standard.  See Section 2.4 Windows SDK Guide to Programming,
  142.  *  page 2-4.
  143.  *
  144.  * Return Value:
  145.  *  See Parameters, above.
  146.  *
  147.  */
  148. #pragma argsused
  149. long FAR PASCAL vxWndProc(HWND hWnd, unsigned iMessage,
  150.                                WORD wParam, LONG lParam)
  151.    {
  152.    HMENU         hMenu;         // handle to main menu
  153.    int           j;             // work integer
  154.    PAINTSTRUCT   ps;            // paint structure
  155.  
  156.    switch (iMessage)
  157.       {
  158.  
  159.       /* handle vxBase initialization procedures when window */
  160.       /* creation message is received                        */
  161.       /* *************************************************** */
  162.       case WM_CREATE:
  163.          vxInit();                // register in multitask list
  164.          vxCtlGraySet();          // set up gray scale
  165.          vxBrowseCase(VX_UPPER);  // default browse case
  166.          vxSetString(VX_ASCIIZ);  // set string types to c strings
  167.          break;
  168.       
  169.       /* on exit, reset system gray and post quit */
  170.       /* **************************************** */
  171.       case WM_DESTROY:
  172.          vxCtlGrayReset();        // reset system grays
  173.          PostQuitMessage(0);      // kill
  174.          break;
  175.  
  176.       /* on paint, draw frame around window */
  177.       /* ********************************** */
  178.       case WM_PAINT:
  179.          BeginPaint(hWnd, &ps);
  180.          vxFormFrame(hWnd);
  181.          EndPaint(hWnd, &ps);
  182.          break;
  183.  
  184.  
  185.       /* ******************************************* */
  186.       /* If user closes from system menu, ensure     */
  187.       /* that multitask closure sequence is correct. */
  188.       /* The first vxbase task loaded MUST be the    */
  189.       /* last one unloaded because it controls the   */
  190.       /* vxbase shareable memory. If the first task  */
  191.       /* is closed, the memory goes with it and any  */
  192.       /* other tasks using vxbase will terminate     */
  193.       /* with an Unrecoverable Application error.    */
  194.       /* ******************************************* */
  195.       case WM_SYSCOMMAND:
  196.          switch (wParam & 0xFFF0)
  197.             {
  198.             case SC_CLOSE:
  199.                /* vxDeallocate will issue a task closure */
  200.                /* sequence error if this task cannot be  */
  201.                /* shut down                              */
  202.                /* ************************************** */
  203.                if (!vxDeallocate())
  204.                   return(TRUE);
  205.  
  206.             /* we could use this switch set to test for   */
  207.             /* other options selcted from the system menu */
  208.             /* ****************************************** */
  209.             default:
  210.                return(DefWindowProc(hWnd, iMessage, wParam, lParam));
  211.             }
  212.  
  213.  
  214.       /* process menu commands */
  215.       /* ********************* */
  216.       case WM_COMMAND:
  217.          switch (wParam)
  218.                         
  219.             {
  220.             case IDM_BROWSE:
  221.  
  222.                // disable menu items
  223.                hMenu = GetMenu(hWnd);
  224.                EnableMenuItem(hMenu, IDM_BROWSE, MF_GRAYED);
  225.                EnableMenuItem(hMenu, IDM_JOIN, MF_GRAYED);
  226.                EnableMenuItem(hMenu, IDM_PACK, MF_GRAYED);
  227.                RetVal = 0;
  228.  
  229.  
  230.                // set up do loop and keep browsing if edit
  231.                // dialog returns a BROWSE_USER value
  232.                while (TRUE)
  233.                   {
  234.  
  235.                   // if browse went ok, vxTypeBrowse returns nonzero
  236.                   if (vxTypeBrowse())
  237.                      {
  238.                      if (RetVal != BROWSE_USER)
  239.                         {
  240.                         MessageBox(hWnd,
  241.                                    rgpsz[IDS_BROWSE],
  242.                                    rgpsz[IDS_CAPTION],
  243.                                    MB_OK | MB_ICONEXCLAMATION);
  244.                         break;
  245.                         }
  246.                      }
  247.  
  248.                   // otherwise an error occurred
  249.                   else
  250.                      {
  251.                      MessageBox(hWnd,
  252.                                 rgpsz[IDE_BROWSE],
  253.                                 rgpsz[IDS_CAPTION],
  254.                                 MB_OK | MB_ICONEXCLAMATION);
  255.                      break;
  256.                      }
  257.                   }
  258.  
  259.                // re-enable menu items
  260.                hMenu = GetMenu(hWnd);
  261.                EnableMenuItem(hMenu, IDM_BROWSE, MF_ENABLED);
  262.                EnableMenuItem(hMenu, IDM_JOIN, MF_ENABLED);
  263.                EnableMenuItem(hMenu, IDM_PACK, MF_ENABLED);
  264.  
  265.                vxWindowDereg(hWnd);
  266.  
  267.                break;
  268.  
  269.  
  270.             case IDM_JOIN:
  271.  
  272.                // disable menu items
  273.                hMenu = GetMenu(hWnd);
  274.                EnableMenuItem(hMenu, IDM_BROWSE, MF_GRAYED);
  275.                EnableMenuItem(hMenu, IDM_JOIN, MF_GRAYED);
  276.                EnableMenuItem(hMenu, IDM_PACK, MF_GRAYED);
  277.                RetVal = 0;
  278.  
  279.  
  280.                // Demonstration of setting up visual relationships
  281.                // with the vxJoin command. What we have is a file of buyers
  282.                // categorized by type of aircraft they are interested in.
  283.                // What we are going to do is display a browse table of
  284.                // these buyer records and link any buyer record to
  285.                // another browse table of aircraft that match the the
  286.                // buyer aircraft type field.
  287.                // --------------------------------------------------------
  288.    
  289.                // open file that will control the join
  290.                // ------------------------------------
  291.                DbfArea1 = vxUseDbf("\\vb\\vxbtest\\airbuyer.dbf");
  292.                NtxArea1 = vxUseNtx("\\vb\\vxbtest\\airbuy2.ntx");
  293.                // this index is on aircraft type
  294.                // ------------------------------
  295.  
  296.                // define table to show data we are interested in
  297.                // ----------------------------------------------
  298.                vxTableDeclare(VX_BLUE, NULL, NULL, 0, 1, 5);
  299.                vxTableField(1, "Type", "b_cat", VX_FIELD);
  300.                vxTableField(2, "Description", "left(b_desc,20)", VX_EXPR);
  301.                vxTableField(3, "Low", "b_low", VX_FIELD);
  302.                vxTableField(4, "High", "b_high", VX_FIELD);
  303.                vxTableField(5, "Customer", "b_code", VX_FIELD);
  304.  
  305.                // now open secondary file and define its table
  306.                // --------------------------------------------
  307.                DbfArea2 = vxUseDbf("\\vb\\vxbtest\\aircraft.dbf");
  308.                NtxArea2 = vxUseNtx("\\vb\\vxbtest\\aircraf2.ntx");
  309.  
  310.                vxTableDeclare(VX_RED, NULL, NULL, 0, 1, 5);
  311.                vxTableField(1, "Type", "c_cat", VX_FIELD);
  312.                vxTableField(2, "Code", "c_code", VX_FIELD);
  313.                vxTableField(3, "Price", "c_price", VX_FIELD);
  314.                vxTableField(4, "Year", "c_year", VX_FIELD);
  315.                vxTableField(5, "TTSN", "c_ttsn", VX_FIELD);
  316.  
  317.                // reselect the master file and set up the join
  318.                // --------------------------------------------
  319.                vxSelectDbf(DbfArea1);
  320.                vxJoin(DbfArea2, NtxArea2, "b_cat", VX_FIELD, "Possible Sales");
  321.  
  322.                // this joins the Aircraft file using the index selected for
  323.                // it to the buyer file. The "b_cat" param is the field we
  324.                // will use as a key into the aircraft file and the VX_FIELD
  325.                // item tells vxBase that it is a field and not an expression.
  326.                // The last item in the call is a title for the join window.
  327.                // -----------------------------------------------------------
  328.  
  329.                // now set up and execute the browse. The JOIN menu item is
  330.                // automatically enabled.
  331.                // ---------------------------------------------------------
  332.                vxBrowse(hWnd, DbfArea1, NtxArea1, FALSE, TRUE, FALSE, 0, "Buyer Details", &RetVal);
  333.  
  334.                // when we return from the browse we can ignore anything
  335.                // vxBase sent back to us in the RetVal param
  336.                // -----------------------------------------------------
  337.                vxClose();
  338.                vxSelectDbf(DbfArea2);
  339.                vxClose();
  340.                vxWindowDereg(hgWnd);
  341.  
  342.                // re-enable menu items
  343.                hMenu = GetMenu(hWnd);
  344.                EnableMenuItem(hMenu, IDM_BROWSE, MF_ENABLED);
  345.                EnableMenuItem(hMenu, IDM_JOIN, MF_ENABLED);
  346.                EnableMenuItem(hMenu, IDM_PACK, MF_ENABLED);
  347.  
  348.                MessageBox(hgWnd,
  349.                            rgpsz[IDS_JOIN],
  350.                            rgpsz[IDS_CAPTION],
  351.                            MB_OK | MB_ICONEXCLAMATION);
  352.  
  353.                break;
  354.  
  355.  
  356.             case IDM_PACK:
  357.                // disable menu items
  358.                hMenu = GetMenu(hWnd);
  359.                EnableMenuItem(hMenu, IDM_BROWSE, MF_GRAYED);
  360.                EnableMenuItem(hMenu, IDM_JOIN, MF_GRAYED);
  361.                EnableMenuItem(hMenu, IDM_PACK, MF_GRAYED);
  362.  
  363.  
  364.                // only pack if file is not in use
  365.                j = vxAreaDbf("\\vb\vxbtest\\airtypes.dbf");
  366.  
  367.                if (!j)
  368.                   {
  369.                   DbfArea1 = vxUseDbf("\\vb\\vxbtest\\airtypes.dbf");
  370.                   NtxArea1 = vxUseNtx("\\vb\\vxbtest\\airtypes.ntx");
  371.                   vxPack(hWnd);
  372.                   vxClose();
  373.                   MessageBox(hgWnd,
  374.                               rgpsz[IDS_PACK],
  375.                               rgpsz[IDS_CAPTION],
  376.                               MB_OK | MB_ICONEXCLAMATION);
  377.                   }
  378.                else
  379.                   MessageBox(hgWnd,
  380.                               rgpsz[IDE_PACK],
  381.                               rgpsz[IDS_CAPTION],
  382.                               MB_OK | MB_ICONEXCLAMATION);
  383.  
  384.                // re-enable menu items
  385.                hMenu = GetMenu(hWnd);
  386.                EnableMenuItem(hMenu, IDM_BROWSE, MF_ENABLED);
  387.                EnableMenuItem(hMenu, IDM_JOIN, MF_ENABLED);
  388.                EnableMenuItem(hMenu, IDM_PACK, MF_ENABLED);
  389.  
  390.                break;
  391.         
  392.  
  393.             /* see WM_SYSCOMMAND above for explanation of */
  394.             /* why we test vxDeallocate before we allow   */
  395.             /* this task to be closed                     */
  396.             /* ****************************************** */
  397.             case IDM_EXIT:
  398.                if (!vxDeallocate())
  399.                   break;
  400.                PostMessage(hWnd, WM_CLOSE, 0, 0L);
  401.                break;
  402.             }
  403.       default:
  404.           return (DefWindowProc(hWnd, iMessage, wParam, lParam));
  405.       }
  406.  
  407.     return 0L;
  408.     }
  409.  
  410.  
  411. /* ***************** */
  412. /* browse types file */
  413. /* ***************** */
  414. int NEAR PASCAL vxTypeBrowse()
  415.    {
  416.    FARPROC        lpProc;        // discardable proc instance
  417.    
  418.    // open dbf file
  419.    DbfArea1 = vxUseDbf("\\vb\\vxbtest\\airtypes.dbf");
  420.    if (!DbfArea1)
  421.       return (FALSE);
  422.  
  423.    // open index file
  424.    NtxArea1 = vxUseNtx("\\vb\\vxbtest\\airtypes.ntx");
  425.    if (!NtxArea1)
  426.       return (FALSE);
  427.  
  428.    // declare browse table
  429.    vxTableDeclare(VX_RED, NULL, NULL, 0, 1, 2);
  430.    vxTableField(1, "Type", "category", VX_FIELD);
  431.    vxTableField(2, "Description", "catname", VX_FIELD);
  432.  
  433.    // set up initial browse position
  434.    vxBrowsePos(20, 10, 50, 15);
  435.  
  436.    // call the browse
  437.    vxBrowse(hgWnd, DbfArea1, NtxArea1, TRUE, TRUE, TRUE, 0L, "Aircraft Types", &RetVal);
  438.  
  439.    // if user closed, exit TRUE
  440.    if (RetVal == BROWSE_CLOSED)
  441.       return (TRUE);
  442.  
  443.    // if browse had error, exit FALSE
  444.    if (RetVal == BROWSE_ERROR)
  445.       return (FALSE);
  446.  
  447.    // if user picked anything else, do file edit dialog
  448.    // NOTE: RetVal is global so it will be accessible to
  449.    //       the edit dialog
  450.    lpProc = MakeProcInstance(vxTypeEditDlg, hgInst);
  451.    DialogBox (hgInst,
  452.             MAKEINTRESOURCE (IDD_TYPEDIT),
  453.             hgWnd,
  454.             lpProc);
  455.    FreeProcInstance(lpProc);
  456.  
  457.    // if user clicks browse button from dialog, retval
  458.    // is set to BROWSE_USER so calling rtn
  459.    // from wm_command can test if this is to be done again
  460.  
  461.    // close file (first ensure registered)
  462.    vxSelectDbf(DbfArea1);
  463.    vxClose();
  464.  
  465.    return (TRUE);
  466.    }
  467.  
  468.  
  469. /* ********************************************************** */
  470. /*           Edit type file record dialog                     */
  471. /* ********************************************************** */
  472. #pragma argsused
  473. BOOL FAR PASCAL vxTypeEditDlg(HWND hdlg, WORD wMsg, WORD wParam, LONG lParam)
  474.    {
  475.           HWND  hwndDI;             /* handle to dialog item   */
  476.           int   j;                  /* general integer         */
  477.    static long  RecNum;             /* current record number   */
  478.    static BOOL  IsChanged;          /* set if anything changes */
  479.    static BOOL  IsDeleting;         /* set on if deleting      */
  480.  
  481.    switch (wMsg)
  482.       {
  483.  
  484.       // initialization routine
  485.       // **********************
  486.       case WM_INITDIALOG:
  487.  
  488.          // register database select area with this window
  489.          vxSelectDbf(DbfArea1);
  490.  
  491.          // set control lengths
  492.          SendDlgItemMessage(hdlg, IDD_TYPE,
  493.                             EM_LIMITTEXT, (WORD)vxFieldSize("category"), 0L);
  494.          SendDlgItemMessage(hdlg, IDD_DESC,
  495.                             EM_LIMITTEXT, (WORD)vxFieldSize("catname"), 0L);
  496.          SendDlgItemMessage(hdlg, IDD_STAT,
  497.                             EM_LIMITTEXT, (WORD)64, 0L);
  498.  
  499.          // disable status bar
  500.          hwndDI = GetDlgItem(hdlg, IDD_STAT);
  501.          EnableWindow(hwndDI, FALSE);
  502.  
  503.          // other init stuff
  504.          RecNum = vxRecNo();              // save record number
  505.          szBuffer[0] = '\0';              // clear work buffer
  506.          IsChanged = FALSE;               // default change val
  507.  
  508.          // analyze browse return value and fill controls accordingly
  509.  
  510.          // if user pressed enter key to select record for edit
  511.          if (RetVal > 0)
  512.             RetVal = BROWSE_EDIT;
  513.  
  514.          // if adding, show empty record
  515.          if (RetVal == BROWSE_ADD)
  516.             {
  517.             SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  518.             SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  519.             SetDlgItemText(hdlg, IDD_STAT, (LPSTR)rgpsz[IDS_ADDING]);
  520.  
  521.             // disable add and delete buttons
  522.             hwndDI = GetDlgItem(hdlg, IDD_ADD);
  523.             EnableWindow(hwndDI, FALSE);
  524.             hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  525.             EnableWindow(hwndDI, FALSE);
  526.             }
  527.  
  528.          // if deleting or editing, show record
  529.          else
  530.             {
  531.             // with any vxbase string function, always copy
  532.             // the result to an internal buffer as below
  533.             // ********************************************
  534.             lstrcpy(szBuffer, (LPSTR)vxField("category"));
  535.             vxbTrim(szBuffer, sizeof(szBuffer));
  536.             SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  537.  
  538.             lstrcpy(szBuffer, (LPSTR)vxField("catname"));
  539.             vxbTrim(szBuffer, sizeof(szBuffer));
  540.             SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  541.  
  542.             if (RetVal == BROWSE_DELETE)
  543.                wsprintf(szBuffer, "%s %ld", (LPSTR)rgpsz[IDS_DELE], RecNum);
  544.             else
  545.                {
  546.                wsprintf(szBuffer, "%s %ld", (LPSTR)rgpsz[IDS_EDIT], RecNum);
  547.                vxUnlock();    // unlock if editing for multiusers
  548.                }
  549.             SetDlgItemText(hdlg, IDD_STAT, (LPSTR)szBuffer);
  550.             }
  551.  
  552.          // if deleting, set switch to send delete
  553.          // button click after form has been painted
  554.          if (RetVal == BROWSE_DELETE)
  555.             IsDeleting = TRUE;
  556.  
  557.          // we can't send the WM_COMMAND message here
  558.          // because the dialog box hasn't been
  559.          // painted yet and we want the user to see
  560.          // the record he is deleting
  561.  
  562.          return (TRUE);  // sets focus to first control
  563.  
  564.  
  565.       // the wm_ctlcolor, wm_paint, and wm_3dpaint create
  566.       // 3d style controls on a gray background
  567.       // ************************************************
  568.       case WM_CTLCOLOR:
  569.          return (Control3dColor(hdlg,wParam));
  570.  
  571.       case WM_PAINT:
  572.          PostMessage(hdlg,WM_3DPAINT,0,0L);
  573.          return (FALSE);
  574.  
  575.       case WM_3DPAINT:
  576.          // frame
  577.          Draw3dFrame(hdlg,OUTSIDE_FRAME);
  578.  
  579.          // edit controls
  580.          Draw3dBorder(hdlg,IDD_TYPE,RECESSED,2);
  581.          Draw3dBorder(hdlg,IDD_DESC,RECESSED,2);
  582.          Draw3dBorder(hdlg,IDD_STAT,RAISED,2);
  583.  
  584.          // buttons
  585.          Draw3dBorder(hdlg,IDD_SAVE,RECESSED,2);
  586.          Draw3dBorder(hdlg,IDD_CANCEL,RECESSED,2);
  587.          Draw3dBorder(hdlg,IDD_ADD,RECESSED,2);
  588.          Draw3dBorder(hdlg,IDD_DELETE,RECESSED,2);
  589.          Draw3dBorder(hdlg,IDD_NEXT,RECESSED,2);
  590.          Draw3dBorder(hdlg,IDD_PREV,RECESSED,2);
  591.          Draw3dBorder(hdlg,IDD_BROWSE,RECESSED,2);
  592.          Draw3dBorder(hdlg,IDD_EXIT,RECESSED,2);
  593.  
  594.          // if deleting, we send a message as if user punched
  595.          // delete button and we process in wm_command
  596.          if (IsDeleting)
  597.             {
  598.             IsDeleting = FALSE;
  599.             hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  600.             lParam = MAKELONG(hwndDI, BN_CLICKED);
  601.             SendMessage(hdlg, WM_COMMAND, IDD_DELETE, lParam);
  602.             }
  603.  
  604.          return (TRUE);
  605.  
  606.       // user pressed a button
  607.       // *********************
  608.       case WM_COMMAND:
  609.          {
  610.          switch (wParam)
  611.             {
  612.             /* *********** */
  613.             /* save button */
  614.             /* *********** */
  615.             case IDD_SAVE:
  616.  
  617.                // get control item "category"
  618.                GetDlgItemText(hdlg, IDD_TYPE, szBuffer, (vxFieldSize("category") + 1));
  619.  
  620.                // convert to upper case and redisplay
  621.                if (lstrlen(szBuffer))
  622.                   {
  623.                   AnsiUpper(szBuffer);
  624.                   SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  625.                   }
  626.                else
  627.                   {
  628.                   MessageBox(hdlg,
  629.                              rgpsz[IDS_BADKEY],
  630.                              rgpsz[IDS_CAPTION],
  631.                              MB_ICONSTOP | MB_OK);
  632.                   hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  633.                   SetFocus(hwndDI);
  634.                   return (FALSE);
  635.                   }
  636.  
  637.                // if new item, test for duplicate key
  638.                if (RetVal == BROWSE_ADD)
  639.                   {
  640.                   if (vxSeek(szBuffer))
  641.                      {
  642.                      vxUnlock();
  643.                      MessageBox(hdlg,
  644.                                 rgpsz[IDS_DUPKEY],
  645.                                 rgpsz[IDS_CAPTION],
  646.                                 MB_ICONSTOP | MB_OK);
  647.                      hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  648.                      SetFocus(hwndDI);
  649.                      return (FALSE);
  650.                      }
  651.  
  652.                   // otherwise add an empty record
  653.                   else
  654.                      vxAppendBlank();
  655.                   }
  656.  
  657.                // if editing position pointer and lock record
  658.                else
  659.                   vxGo(RecNum);
  660.  
  661.                // get catname field data and put fields away
  662.                GetDlgItemText(hdlg, IDD_DESC, szBuffer2, (vxFieldSize("catname") + 1));
  663.                vxReplString("category", szBuffer);
  664.                vxReplString("catname", szBuffer2);
  665.                vxWrite();
  666.  
  667.                // update status box
  668.                RecNum = vxRecNo();
  669.                if (RetVal == BROWSE_ADD)
  670.                   wsprintf(szBuffer, "Record %ld appended", RecNum);
  671.                else
  672.                   wsprintf(szBuffer, "Record %ld saved", RecNum);
  673.                SetDlgItemText(hdlg, IDD_STAT, (LPSTR)szBuffer);
  674.  
  675.                // update buttons
  676.                hwndDI = GetDlgItem(hdlg, IDD_SAVE);
  677.                EnableWindow(hwndDI, TRUE);
  678.                hwndDI = GetDlgItem(hdlg, IDD_CANCEL);
  679.                EnableWindow(hwndDI, TRUE);
  680.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  681.                EnableWindow(hwndDI, TRUE);
  682.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  683.                EnableWindow(hwndDI, TRUE);
  684.  
  685.                // unlock record
  686.                vxUnlock();
  687.  
  688.                // change status to edit mode
  689.                RetVal = BROWSE_EDIT;
  690.  
  691.                return (TRUE);
  692.  
  693.  
  694.             /* ************* */
  695.             /* cancel button */
  696.             /* ************* */
  697.             case IDD_CANCEL:
  698.  
  699.                // clear form data and reset buttons
  700.                szBuffer[0] = '\0';              // clear work buffer
  701.                SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  702.                SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  703.                SetDlgItemText(hdlg, IDD_STAT, (LPSTR)rgpsz[IDS_CANC]);
  704.  
  705.                hwndDI = GetDlgItem(hdlg, IDD_SAVE);
  706.                EnableWindow(hwndDI, FALSE);
  707.                hwndDI = GetDlgItem(hdlg, IDD_CANCEL);
  708.                EnableWindow(hwndDI, FALSE);
  709.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  710.                EnableWindow(hwndDI, TRUE);
  711.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  712.                EnableWindow(hwndDI, FALSE);
  713.  
  714.                // disable data entry
  715.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  716.                EnableWindow(hwndDI, TRUE);
  717.                hwndDI = GetDlgItem(hdlg, IDD_DESC);
  718.                EnableWindow(hwndDI, TRUE);
  719.  
  720.                return (TRUE);
  721.  
  722.             /* ********** */
  723.             /* add button */
  724.             /* ********** */
  725.             case IDD_ADD:
  726.                // test if current stuff has changed
  727.                for (j=IDD_TYPE; j<IDD_DESC; j++)
  728.                   if (SendDlgItemMessage(hdlg, j, EM_GETMODIFY, 0, 0L))
  729.                      IsChanged = TRUE;
  730.                if (IsChanged)
  731.                   {
  732.                   IsChanged = FALSE;
  733.                   if (IDNO == (MessageBox(hdlg, "Current record changed. Abandon?",
  734.                                rgpsz[IDS_CAPTION],
  735.                                MB_ICONQUESTION | MB_YESNO)))
  736.                       return (TRUE);
  737.  
  738.                   }
  739.                IsChanged = FALSE;
  740.  
  741.                // clear controls 
  742.                szBuffer[0] = '\0';              // clear work buffer
  743.                SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  744.                SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  745.                SetDlgItemText(hdlg, IDD_STAT, (LPSTR)rgpsz[IDS_ADDING]);
  746.  
  747.                // disable add and delete buttons
  748.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  749.                EnableWindow(hwndDI, FALSE);
  750.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  751.                EnableWindow(hwndDI, FALSE);
  752.  
  753.                // enable data entry
  754.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  755.                EnableWindow(hwndDI, TRUE);
  756.                hwndDI = GetDlgItem(hdlg, IDD_DESC);
  757.                EnableWindow(hwndDI, TRUE);
  758.  
  759.  
  760.                // set add mode
  761.                RetVal = BROWSE_ADD;
  762.  
  763.                // set focus to code
  764.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  765.                SetFocus(hwndDI);
  766.  
  767.                // when setting focus, always return false
  768.                return (FALSE);
  769.  
  770.  
  771.             /* ************* */
  772.             /* delete button */
  773.             /* ************* */
  774.             case IDD_DELETE:
  775.  
  776.                // confirm deletion
  777.                if (IDNO == (MessageBox(hdlg,
  778.                                        rgpsz[IDS_CDELE],
  779.                                        rgpsz[IDS_CAPTION],
  780.                                        MB_ICONQUESTION | MB_YESNO)))
  781.                   {
  782.                   SetDlgItemText(hdlg, IDD_STAT, "Delete cancelled");
  783.                   RetVal = BROWSE_EDIT;
  784.                   return (TRUE);
  785.                   }
  786.  
  787.                vxLockRecord();
  788.                vxDeleteRec();
  789.                wsprintf(szBuffer, "Record %ld deleted", RecNum);
  790.                SetDlgItemText(hdlg, IDD_STAT, (LPSTR)szBuffer);
  791.  
  792.                // clear data and reset buttons
  793.                szBuffer[0] = '\0';              // clear work buffer
  794.                SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  795.                SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  796.  
  797.                hwndDI = GetDlgItem(hdlg, IDD_SAVE);
  798.                EnableWindow(hwndDI, FALSE);
  799.                hwndDI = GetDlgItem(hdlg, IDD_CANCEL);
  800.                EnableWindow(hwndDI, FALSE);
  801.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  802.                EnableWindow(hwndDI, TRUE);
  803.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  804.                EnableWindow(hwndDI, FALSE);
  805.  
  806.                // disable data entry
  807.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  808.                EnableWindow(hwndDI, TRUE);
  809.                hwndDI = GetDlgItem(hdlg, IDD_DESC);
  810.                EnableWindow(hwndDI, TRUE);
  811.  
  812.                RetVal = 0;
  813.                vxUnlock();
  814.                return (TRUE);
  815.  
  816.  
  817.             /* *********** */
  818.             /* next button */
  819.             /* *********** */
  820.             case IDD_NEXT:
  821.                // first test if current rec has changed
  822.                for (j=IDD_TYPE; j<IDD_DESC; j++)
  823.                   if (SendDlgItemMessage(hdlg, j, EM_GETMODIFY, 0, 0L))
  824.                      IsChanged = TRUE;
  825.                if (IsChanged)
  826.                   {
  827.                   IsChanged = FALSE;
  828.                   if (IDNO == (MessageBox(hdlg, "Current record changed. Abandon?",
  829.                                rgpsz[IDS_CAPTION],
  830.                                MB_ICONQUESTION | MB_YESNO)))
  831.                       return (TRUE);
  832.  
  833.                   }
  834.                IsChanged = FALSE;
  835.  
  836.                // skip unless eof; ignore deleted records
  837.                while (TRUE)
  838.                   {
  839.                   vxSkip(1L);
  840.                   if (vxEof())
  841.                      break;
  842.                   if (!vxDeleted())
  843.                      break;
  844.                   }
  845.  
  846.                if (vxEof())
  847.                   {
  848.                   MessageBeep(0);
  849.                   SetDlgItemText(hdlg, IDD_STAT, "End of file");
  850.                   vxBottom();
  851.                   RecNum = vxRecNo();
  852.                   }
  853.                else
  854.                   {
  855.                   RecNum = vxRecNo();
  856.                   wsprintf(szBuffer, "Skipped to record %ld", RecNum);
  857.                   SetDlgItemText(hdlg, IDD_STAT, (LPSTR)szBuffer);
  858.                   }
  859.  
  860.                lstrcpy(szBuffer, (LPSTR)vxField("category"));
  861.                vxbTrim(szBuffer, sizeof(szBuffer));
  862.                SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  863.  
  864.                lstrcpy(szBuffer, (LPSTR)vxField("catname"));
  865.                vxbTrim(szBuffer, sizeof(szBuffer));
  866.                SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  867.  
  868.                RetVal = BROWSE_EDIT;
  869.  
  870.                hwndDI = GetDlgItem(hdlg, IDD_SAVE);
  871.                EnableWindow(hwndDI, TRUE);
  872.                hwndDI = GetDlgItem(hdlg, IDD_CANCEL);
  873.                EnableWindow(hwndDI, TRUE);
  874.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  875.                EnableWindow(hwndDI, TRUE);
  876.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  877.                EnableWindow(hwndDI, TRUE);
  878.  
  879.                // set focus to code
  880.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  881.                SetFocus(hwndDI);
  882.                return (FALSE);
  883.  
  884.  
  885.             /* *********** */
  886.             /* prev button */
  887.             /* *********** */
  888.             case IDD_PREV:
  889.                // first test if current rec has changed
  890.                for (j=IDD_TYPE; j<IDD_DESC; j++)
  891.                   if (SendDlgItemMessage(hdlg, j, EM_GETMODIFY, 0, 0L))
  892.                      IsChanged = TRUE;
  893.                if (IsChanged)
  894.                   {
  895.                   IsChanged = FALSE;
  896.                   if (IDNO == (MessageBox(hdlg, "Current record changed. Abandon?",
  897.                                rgpsz[IDS_CAPTION],
  898.                                MB_ICONQUESTION | MB_YESNO)))
  899.                       return (TRUE);
  900.  
  901.                   }
  902.                IsChanged = FALSE;
  903.  
  904.                // skip unless bof; ignore deleted records
  905.                while (TRUE)
  906.                   {
  907.                   vxSkip(-1L);
  908.                   if (vxBof())
  909.                      break;
  910.                   if (!vxDeleted())
  911.                      break;
  912.                   }
  913.  
  914.                if (vxBof())
  915.                   {
  916.                   MessageBeep(0);
  917.                   SetDlgItemText(hdlg, IDD_STAT, "Beginning of file");
  918.                   vxTop();
  919.                   RecNum = vxRecNo();
  920.                   }
  921.                else
  922.                   {
  923.                   RecNum = vxRecNo();
  924.                   wsprintf(szBuffer, "Skipped to record %ld", RecNum);
  925.                   SetDlgItemText(hdlg, IDD_STAT, (LPSTR)szBuffer);
  926.                   }
  927.  
  928.                // load data
  929.                lstrcpy(szBuffer, (LPSTR)vxField("category"));
  930.                vxbTrim(szBuffer, sizeof(szBuffer));
  931.                SetDlgItemText(hdlg, IDD_TYPE, (LPSTR)szBuffer);
  932.  
  933.                lstrcpy(szBuffer, (LPSTR)vxField("catname"));
  934.                vxbTrim(szBuffer, sizeof(szBuffer));
  935.                SetDlgItemText(hdlg, IDD_DESC, (LPSTR)szBuffer);
  936.  
  937.                RetVal = BROWSE_EDIT;
  938.  
  939.                // reset buttons
  940.                hwndDI = GetDlgItem(hdlg, IDD_SAVE);
  941.                EnableWindow(hwndDI, TRUE);
  942.                hwndDI = GetDlgItem(hdlg, IDD_CANCEL);
  943.                EnableWindow(hwndDI, TRUE);
  944.                hwndDI = GetDlgItem(hdlg, IDD_ADD);
  945.                EnableWindow(hwndDI, TRUE);
  946.                hwndDI = GetDlgItem(hdlg, IDD_DELETE);
  947.                EnableWindow(hwndDI, TRUE);
  948.  
  949.                // set focus to code
  950.                hwndDI = GetDlgItem(hdlg, IDD_TYPE);
  951.                SetFocus(hwndDI);
  952.                return (FALSE);
  953.  
  954.  
  955.             /* ************* */
  956.             /* browse button */
  957.             /* ************* */
  958.             case IDD_BROWSE:
  959.                // first test if current rec has changed
  960.                for (j=IDD_TYPE; j<IDD_DESC; j++)
  961.                   if (SendDlgItemMessage(hdlg, j, EM_GETMODIFY, 0, 0L))
  962.                      IsChanged = TRUE;
  963.                if (IsChanged)
  964.                   {
  965.                   IsChanged = FALSE;
  966.                   if (IDNO == (MessageBox(hdlg, "Current record changed. Abandon?",
  967.                                rgpsz[IDS_CAPTION],
  968.                                MB_ICONQUESTION | MB_YESNO)))
  969.                       return (TRUE);
  970.  
  971.                   }
  972.                RetVal = BROWSE_USER;
  973.                EndDialog(hdlg, TRUE);
  974.                return (TRUE);
  975.  
  976.  
  977.             /* *********** */
  978.             /* exit button */
  979.             /* *********** */
  980.             case IDD_EXIT:
  981.                // first test if current rec has changed
  982.                for (j=IDD_TYPE; j<IDD_DESC; j++)
  983.                   if (SendDlgItemMessage(hdlg, j, EM_GETMODIFY, 0, 0L))
  984.                      IsChanged = TRUE;
  985.                if (IsChanged)
  986.                   {
  987.                   IsChanged = FALSE;
  988.                   if (IDNO == (MessageBox(hdlg, "Current record changed. Abandon?",
  989.                                rgpsz[IDS_CAPTION],
  990.                                MB_ICONQUESTION | MB_YESNO)))
  991.                       return (TRUE);
  992.  
  993.                   }
  994.                RetVal = 0;           // clear RetVal before return
  995.                EndDialog(hdlg, TRUE);
  996.                return (TRUE);
  997.             }
  998.          }
  999.  
  1000.       default:
  1001.          break;
  1002.       }
  1003.       return (FALSE);
  1004.    }
  1005.  
  1006.  
  1007.  
  1008. /* ************************************************************
  1009.  * HLoadAppStrings
  1010.  *
  1011.  * Purpose:
  1012.  *  Allocates FIXED local memory and reads the applications
  1013.  *  string resources into that memory.  Each string's pointer
  1014.  *  is available with rgpsz[i] where i is the ID value of the
  1015.  *  string.  The strings must have sequential IDs.
  1016.  *
  1017.  * Parameters:
  1018.  *  none
  1019.  *
  1020.  * Return Value:
  1021.  *  HANDLE    Handle to the local memory.  NULL if memory could
  1022.  *            not be allocated.
  1023.  *
  1024.  * ************************************************************ */
  1025.  
  1026. HANDLE NEAR PASCAL HLoadAppStrings(void)
  1027.     {
  1028.     HANDLE      hLocalMem;
  1029.     char NEAR   *pch;
  1030.     WORD        cchUsed = 0;
  1031.     WORD        cch;
  1032.     short       i;
  1033.  
  1034.     /*
  1035.      * Allocate memory and load strings.  NOTE!  The LPTR style
  1036.      * specifies FIXED memory.  This should not be a big deal
  1037.      * since this is an early allocation into the local heap.
  1038.      * But it should be watched if the number of strings becomes
  1039.      * large.
  1040.      */
  1041.     hLocalMem = LocalAlloc(LPTR, CSTRINGS*CCHSTRINGMAX);
  1042.  
  1043.     if (hLocalMem == NULL)
  1044.         return (HANDLE)NULL;
  1045.  
  1046.     /*
  1047.      * This operation is only valid for FIXED memory.  Otherwise use
  1048.      * LocalLock.
  1049.      */
  1050.     pch = (char *)hLocalMem;
  1051.  
  1052.     /*
  1053.      * Load the strings into the memory and retain the specific
  1054.      * pointer to that string.
  1055.      */
  1056.     for (i = 0; i < CSTRINGS; i++)
  1057.         {
  1058.         cch = LoadString(hgInst, i, (LPSTR)(pch + cchUsed), CCHSTRINGMAX - 1);
  1059.         rgpsz[i] = (char *)(pch + cchUsed);
  1060.  
  1061.         /*
  1062.          * One is added to cch to include a NULL.  The memory was ZEROINITed
  1063.          * on allocation so by skipping a byte we get the NULL.
  1064.          */
  1065.         cchUsed += (cch + 1);
  1066.         }
  1067.  
  1068.     /*
  1069.      * It is assumed that no string is over CCHSTRINGMAX, and therefore
  1070.      * not all the allocated memory was used. Therefore LocalReAlloc
  1071.      * will only SHRINK the block, never expand it.  So if it fails, there's
  1072.      * no problem--all the strings are still there, with some wasted
  1073.      * space.
  1074.      */
  1075.     LocalReAlloc(hLocalMem, cchUsed+1, LPTR);
  1076.  
  1077.     return hLocalMem;
  1078.     }
  1079.  
  1080. /*
  1081.  ┌──────────────────────────────────────────────────────────────────────────┐
  1082.  │ END                                                                      │
  1083.  └──────────────────────────────────────────────────────────────────────────┘
  1084. */
  1085.  
  1086.