vxBase 3.07  August 11, 1993
----------------------------
This is a new major release of vxBase numbered 3.0X. It contains a new set of
functions designed to store, manage, and retrieve bitmaps. It also contains
a set of functions that will create and maintain permanent subindexes - plus
MORE. In all, 20 new functions have been added.

Changes to version vxBase 2.xx are documented after the new function
writeups.

NOTE: Release 3.02 adds function vxLockRetry which allows much greater
      flexibility in locking protocol and error reporting. See below.

      Release 3.03 increases max filter string length to 1024 from 512
      and also now respects filters in child files in vxSetRelation
      chains.

      Release 3.04 corrects vxPack problem (640/1602 error) when every
      record in the 64k read buffer was deleted.

      Release 3.05 adds function vxPicturePrint and the following
      elements to the xBase expression parsing engine:
        function ALLTRIM()  trims right and left
        functiom EMPTY()    true if string is all spaces, blank date, 
                            or 0 numeric value or .F. logical
        operator !          equivalent to .NOT.
        operator ==         exactly equal
        #                   not equal (equivalent to <>)
        !=                  not equal (equivalent to <>) 

      Release 3.06 adds:
        (1) sub function vxSetGauge allows the programmer
            to use his own gauge controls in vxReindex, vxPack, etc.
        (2) new vxCtlBrowseMsg messages VXB_GO, VXB_SKIP (see below).
        (3) quasi-xBase function TIMEODAY(). TIMEODAY(val) converts a number
            (either literal or contained in a numeric field) representing
            minutes into a string representing the time of day
            (e.g., TIMEODAY(510) = "08:30 am".
        (4) "Exit" item aded to vxMemoEdit window.
        (5) minor positioning and scroll problems corrected in vxCtlBrowse.
        (6) xBase expressions that do not have their elements separated by
            spaces now parse properly (e.g., (Y_N1.and.Y_N2) formerly 
            returned an error unless ".and." was separated from the field
            names by spaces).

      Release 3.07 Bug Fixes:
         (1) memo overwrite caused by 3.02 corrected.
         (2) vxNumRecsSub corrected
         (3) vxNtxRecNo positioning after call corrected     
         (4) index corruption when appending key to subindex corrected


BITMAPS
-------
The bitmaps are stored in standard xBase memo files. Fields in the dbf which
contain block references to the bitmaps are standard type "M" fields. An
attempt to display the bitmap using third party xBase software (e.g., Clipper
or even the current release of DataWorks) will show "BIT*MAP". If these
memos are replaced with text, the bitmaps will be lost.

An updated vxbtest project is included in the zip. To show off the bitmap
functions, run it and select "Link" and then "Show Pictures" from the
main menu. The code that shows the bitmaps is in VYFORM2. If you are running
the sample on a low resolution monitor (i.e., 640x480), maximize 
the form. You should also make the vxCtlBrowse box a little wider and
deeper. 

Collecting Bitmaps
------------------
Images stored in a vxBase memo file are most easily transferred via
a bitmap file (files with .BMP extensions).

vxBase takes advantage of the rich body of functions included in Visual
Basic to handle bitmap files. Bitmaps are the Windows norm; all paint
programs, viewers, etc. can handle bitmaps - and most programs that
deal with pictures can convert foreign formats (e.g., GIF) to BMPs.
As a last resort, cut a picture into the clipboard and paste it into a 
Windows PAINT window. It can then be stored as a .BMP file. 

Once an image is stored in a BMP file it can be transferred to the 
memo file with the vxPictureImport function. To retrieve the bitmap,
vxBase uses the standard Windows Clipboard. It puts the bitmap out to
the clipboard as a DIB (device independent bitmap). The Visual Basic
Clipboard.GetData(8) function then is used to retrieve the image
from the clipboard and display it in a VB Picture Box. The box
can have the AUTORESIZE property set to TRUE as in the sample
application if the images are all different sizes

C programmers can store ANY KIND of BLOB (binary large object) in a memo 
file with vxBlobWrite and retrieve the BLOBs with vxBlobRead. Contact the
author for more information on these functions.


SUBINDEXES
----------
A subindex is an index that represents a defined subset of records in the
main dbf file. The indexing expression is in no way related to the
conditional expression that determines whether or not the record will be 
represented in the index. In other words, the condition that determines
the presence or absence of a key does not depend upon the value of the
key. For example, a subindex may be created using the expression
"upper(custname)" as the key. The conditional expression could be
"(left(vxcountry,6)="CANADA") .or. (left(vxcountry,6)="U.S.A.". This
would produce an index that represented customers in North America only.
An open subindex in an index list attached to a database is maintained
just as like other index. When a record is added, an index key for the
record is only added if the conditional expression evaluates as TRUE.
If a record is updated, and the update data invalidates the record
for inclusion in the subindex, the key is deleted.

If you regularly filter data based upon a condition such as the one
above, a permanent subindex makes data retrieval MUCH faster. If the
file is large, and you need to set a temporary filter that may result
in very long record retrieval times, it is probably faster to create
a temporary subindex instead. A subindex makes it APPEAR that the database
contains only records that satisfy the conditional logical expression.


COMPATIBILITY ISSUES
--------------------
With release 3.0X, vxBase breaks away from strict xBase standards. Bitmaps
of course may only be retrieved and displayed using vxBase functions.
The header block of a subindex also differs from a standard Clipper NTX
index header block. New elements have been added that define whether or
not the index is a subindex and an area is used to hold the conditional
expression as well. 

Release 5.2 of CA-Clipper changes the index header as well and also changes
the index locking scheme. vxBase NTX indexes ARE NOT COMPATIBLE with Clipper
5.2 indexes. Indexes created and/or maintained with any version of Clipper
will NOT properly maintain a vxBase subindex.

Bitmaps and subindexes are specialty items requested by a great many vxBase
users. If compatibility is an issue with your application, it would be best
not to use these functions (although bitmaps may be safely ignored; if the
memo text returns "BIT*MAP" then it may be ignored in a Clipper application).


vxCtlBrowseMsg
--------------
A new message type has been created to extract the current contents of the
user entered quick key value. Define the message in your global module as

Global Const VXB_QUICKDISPLAY = 12

A quick key entry will normally result in a the record pointer being
moved so the KeyCode middle button down event generated by vxCtlBrowse
whenever a new record is highlighted may be used to conveniently ask 
for the current quick value. The new message may be used to display
the current quick value in a text box as follows:

Sub BrowseBox_KeyDown (KeyCode As Integer, Shift As Integer)
'   Debug.Print KeyCode
   If KeyCode = 4 Then
      QWinLong& = vxCtlHwnd(QuickBox) 
      ' Note: vxCtlHwnd normally returns an integer but you
      ' must explicitly cast its value as a long integer
      ' in order to fulfill the vxCtlBrowseMsg parameter
      ' requirements 
      k& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_QUICKDISPLAY, ByVal QWinLong&)
   End If
End Sub

Note: A VB label MAY NOT BE USED to display the quick value because a
label is a "graphical object" and therefore does not have a window 
handle.

New array positioning messages:

Global Const VXB_GO = 13

Positions the highlight to a specific record contained in the current browse
display. This is especially useful if you are updating a record on a detail
form and, after you are done, you wish to refresh the browse table with the
new information and then position the highlight to the record that was just 
updated (VXB_REFRESH always positions the highlight to the top record in the
browse). Param is passed BYVAL as a dbf record number to the browse. You must
ensure that the record number passed is indeed pointing to a record on the
current browse display. The return value may be ignored. 

Example:
Sub ButtonSave_Click ()
   SaveRecNo& = CurrentRec
   TopRec& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GETTOPREC, 0)
   j% = vxSelectDbf(vxClientDbf)
   j% = vxGo(CurrentRec)
   j% = vxLockRecord()
   Call vxReplString("vxnamekey", (BoxNAMEKEY.Text))
   Call vxReplString("vxcompany", (BoxCOMPANY.Text))
   j% = vxWrite()
   j% = vxWriteHdr()
   j% = vxUnlock()
   k& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_REFRESH, ByVal TopRec&)
   k& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GO, ByVal SaveRecNo&)
End Sub

Global Const VXB_SKIP = 14
Moves the highlight up or down in the browse table (if param is passed as a negative
number the movement is UP; 0 or a positive number moves DOWN). If the highlight is
positioned at the top or bottom record in the display, the browse will scroll. This
is useful where you have a browse table on one side of the screen and detail info
about the highlighted record on the other side of the screen or even on a different
form.  If the detail side has a Previous or Next button on it, you can synchronize the
highlight on the browse table to the detail record data. The return value may be ignored.

Example:
Sub ButtonNext_Click ()
   If RecChange Then
      j% = MsgBox("Record changed. Save?", 52)
      If j% = 6 Then
         ButtonSave_Click
      End If
   End If

   CurrentRec = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GETCURRENTREC, 0)
   j% = vxGo(CurrentRec)

   ' skip forward one record
   ' -----------------------
   j% = vxSelectDbf(vxClientDbf)
   j% = vxSkip(1)
   
   ' test for end of file
   ' --------------------
   If vxEof() Then
      Beep
      VXFORM1.StatBar.Text = "End of File!"
      j% = vxGo(CurrentRec)
   Else
      VXFORM1.StatBar.Text = "Skipped to record " + LTrim$(Str$(vxRecNo()))
      CurrentRec = vxRecNo()
      CurrentRec = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_SKIP, ByVal 1&)
      ButtonEdit_Click
   End If
End Sub


NEW FUNCTIONS
-------------

vxBlobRead
----------
Declaration:
HANDLE FAR PASCAL  vxBlobRead (memofieldname)
char*  memofieldname;          /* name of memo field holding blob */ 

Purpose:
   Read a binary large object (blob) from a memo file that was stored with
vxBlobWrite.

Parameters:
   memofieldname is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   A HANDLE to global memory allocated by vxBase. The memory contains
the blob. It is the programmer's responsibility to release the memory
with GlobalFree when he is done with it.

Usage:
   Any binary object may be stored in a memo field with vxBlobWrite and
a HANDLE to that object may be extracted with vxBlobRead. The vxPicture
functions are limited to standard BMPs and variants thereof. 

Example:

/* ********************************************* */
/* DrawBlob uses a GIF library to place an       */
/* image into the window passed to the function  */
/* The blob is retrieved from the memo fieldname */
/* stored in the current record                  */
/* ********************************************* */
BOOL DrawBlob(HWND hwnd, char *fieldname)
{
   HANDLE     hPicBuffer;      // mem handle to blob
   LPSTR      lpPicBuffer;     // string addr of blob

   // get the handle to the blob
   // if NULL, return FALSE
   // ---------------------------
   hPicBuffer = vxBlobRead(fieldname);
   if (!hPicBuffer)
      return(FALSE);
   
   // convert the handle to a string address
   // --------------------------------------
   lpPicBuffer = GlobalLock(hPicBuffer);

   // Draw the image
   // --------------
   if (!GifConverter(hwnd, lpPicBuffer))
      {
      GlobalUnlock(hPicBuffer);
      GlobalFree(hPicBuffer);
      return(FALSE);
      }

   // release the memory
   // ------------------
   GlobalUnlock(hPicBuffer);
   GlobalFree(hPicBuffer);
   return(TRUE);
}

See Also:
   vxBlobWrite, vxIsPicture, vxPictureImport, vxPictureRead, vxMemoClear


vxBlobWrite
-----------
Declaration:
int FAR PASCAL  vxBlobWrite (hGlobal, memofieldname)
HANDLE hGlobal;           // global handle to mem storing blob        
char*  memofieldname;     // name of memo field to put it in

Purpose:
   Write a binary large object (blob) into a memo file.

Parameters:
   hGlobal is a handle to a global memory object that stores a
binary large object.

   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   TRUE if the operation was successful and FALSE if not.

Usage:
   Any binary object may be stored in a memo field with vxBlobWrite and
a HANDLE to that object may be extracted with vxBlobRead. The vxPicture
functions are limited to standard BMPs and variants thereof. 
   vxBase does not free the global memory after writing the blob. That
is the programmer's responsibility.

Example:

/* ********************************************** */
/* GetBlob stores a GIF image into a memo field   */
/* The blob is retrieved from the filename passed */
/* to this function                               */
/* ********************************************** */
BOOL GetBlob(char *filename, char *fieldname)
{

   int        hFile;           // dos file handle
   DWORD      dwLength;        // import file length
   HANDLE     hPicBuffer;      // mem handle to blob
   LPSTR      lpPicBuffer;     // string addr of blob

   //  verify existence of import file
   // --------------------------------
   hFile = myFileOpen(filename, 0);
   if (hFile < 0)      // if error, return FALSE
      return(FALSE);
      

   // if zero length, set error
   // -------------------------
   dwLength = myFileLength(hFile);
   if (!dwLength)
      return(FALSE);
 
   // if unable to allocate memory, set error
   // ---------------------------------------
   if (NULL == (hPicBuffer = GlobalAlloc(GHND, (DWORD)dwLength)))
      {
      _lclose(hFile);
      return(FALSE);
      }

   // read image
   // ----------
   lpPicBuffer = GlobalLock(hPicBuffer);
   _hread(hFile, lpPicBuffer, (DWORD) dwLength); // huge read
   _lclose(hFile);

   // write image to memo file
   // ------------------------
   GlobalUnlock(hPicBuffer);
   if (!vxBlobWrite(hPicBuffer, fieldname))
      {
      GlobalFree(hPicBuffer);
      return(FALSE);
      }

   GlobalFree(hPicBuffer);
   return(TRUE);
}

See Also:
   vxBlobRead, vxIsPicture, vxPictureImport, vxPictureRead, vxMemoClear


vxCreateSubNtx
--------------
Declaration:
   Declare Function vxCreateSubNtx Lib "vxbase.dll" (ByVal NewNtxName
As String, ByVal NtxExpr As String, ByVal ForCond As String) As Integer

Purpose:
   Create a permanent subindex that represents a defined subset of
records in the main dbf file. Only records that pass the test of
the defined conditional logical expression are included in the index.

Parameters:
   NewNtxName is the name of the new index file that is created. The
parameter may be a literal string or a string variable. It may include
a complete path name. If an extension is not specified, vxBase defaults
it to ".ntx". An existing file with the same name is overwritten. File
names must begin with a letter. The file name length is limited by DOS
to 8 characters.

   NtxExpr is a valid xBase expression (which may be as simple as a 
field name) that is passed as either a literal string or as a string
variable. Maximum length of the expression is 255 characters.

   ForCond is a valid xBase expression that evaluates as a logical
TRUE or FALSE. The index built by vxCreateSubNtx is composed of
keys built from records that satisfy the ForCond expression. The ForCond
expression may be passed as either a literal string or as a string
variable. Maximum length of the expression is 255 characters.

Usage:
   A subindex is an index that represents a defined subset of records in the
main dbf file. The indexing expression is in no way related to the
conditional expression that determines whether or not the record will be 
represented in the index. In other words, the condition that determines
the presence or absence of a key does not depend upon the value of the
key. For example, a subindex may be created using the expression
"upper(custname)" as the key. The conditional expression could be
"(left(vxcountry,6)="CANADA") .or. (left(vxcountry,6)="U.S.A.". This
would produce an index that represented customers in North America only.
An open subindex in an index list attached to a database is maintained
just as like other index. When a record is added, an index key for the
record is only added if the conditional expression evaluates as TRUE.
If a record is updated, and the update data invalidates the record
for inclusion in the subindex, the key is deleted.

   If you regularly filter data based upon a condition such as the one
above, a permanent subindex makes data retrieval MUCH faster. If the
file is large, and you need to set a temporary filter that may result
in very long record retrieval times, it is probably faster to create
a temporary subindex instead. A subindex makes it APPEAR that the database
contains only records that satisfy the conditional logical expression.


Warning:
   If you are editing a file that is being controlled by a subindex (i.e.,
the index currently selected), field changes or additions that result in
the for condition returning FALSE will leave the record pointer in an
undefined state after the record is saved. If the record is an update,
the key will be removed from the index. If the record is an addition,
the key will not be added to the index. IT IS YOUR RESPONSIBILTY to
position the record pointer to a valid record if this should occur.
   There are a number of ways this can be accomplished. If you know
the condition, you can test if the new data will qualify the record
for inclusion in the index. Or you may simply seek for the record again
after writing. If it does not exist, you can position the record
pointer to someplace you have prepared to go to before you began the
update routine. This is the strategy used below:

Example (Updating a subindexed file safely):
--------------------------------------------

' Validate data when save button is pressed
' -----------------------------------------
Sub CustSave_Click ()
   ' verify something in the field
   ' -----------------------------
   j% = vxSelectDbf(vxClientDbf)
   SeekKey$ = CustCode.Text
   If EmptyString(SeekKey$) Then
      MsgBox "vxSer Field cannot be empty"
      Exit Sub
   End If

   ' reread the record
   ' -----------------
   j% = vxSeek(SeekKey$)
   ThisRec& = vxRecNo()

   ' now get previous record in case
   ' in a subindex situation the changes
   ' the user makes removes this record
   ' from the index. 
   ' The subindex condition here is
   ' vxCountry = 'CANADA' .or. vxCountry = 'U.S.A.'
   ' If the user has changed the country to 
   ' something else, this record will disappear
   ' from the index when it is written so we
   ' must plan on what to do of this happens.
   ' ----------------------------------------------
   j% = vxSkip(-1)
   If vxBof() Then
      j% = vxTop()
   End If
   PrevRec& = vxRecNo()

   ' put record pointer back to update
   ' ---------------------------------
   j% = vxGo(ThisRec&)

   ' Data passed. Put it away
   ' ------------------------
   j% = vxLockRecord()
   Call vxReplString("vxcompany", (CustCompany.Text))
   Call vxReplString("vxname", (CustName.Text))
   Call vxReplString("vxaddress1", (CustAddress.Text))
   Call vxReplString("vxaddress2", (CustAddress2.Text))
   Call vxReplString("vxcity", (CustCity.Text))
   Call vxReplString("vxstate", (CustState.Text))
   Call vxReplString("vxcountry", (CustCountry.Text))
   Call vxReplString("vxzip", (CustZip.Text))
   Call vxReplString("vxphone", (CustPhBus.Text))
   Call vxReplString("vxfax", (CustFax.Text))
   j% = vxWrite()
   j% = vxWriteHdr()
   j% = vxUnlock()

   ' Update status box
   ' -----------------
   VXFORM1.StatBar.Text = "Record " + LTrim$(Str$(ThisRec&)) + " saved"

   ' Now see if the record still exists in this index.
   ' If it doesnt exist, the country has been changed
   ' so we will go to the Previous record we saved 
   ' above and load the form data with that. Otherwise,
   ' this record data will remain on the form.
   ' -------------------------------------------------
   If Not vxSeek(SeekKey$) Then
      j% = vxGo(PrevRec&)
      CustDataLoad
   End If
   
   CustReturn = BROWSE_EDIT
   RecChange = False
End Sub

Example (Creating a subindex):
  ' we open a subindex just as we do a normal index
  ' UserFname$ contains the path and name of the subindex
  If Not vxFile(UserFname$) Then
     vxCl1Ntx = vxCreateSubNtx(UserFname$, "vxser", "left(vxcountry,6)='CANADA'
 .or. left(vxcountry,6)='U.S.A.'")
  Else
     vxCl1Ntx = vxUseNtx(UserFname$)
  End If

See Also:
   vxCreateNtx, vxIsSubNtx, vxNtxSubExpr, vxNumRecsSub, vxUseNtx


vxIsPicture
-----------
Declaration:
   Declare Function vxIsPicture Lib "vxbase.dll" (ByVal MemoFieldName
As String) As Integer

Purpose:
   Determine whether a bitmap is attached to the defined memo field.

Parameters:
   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
  TRUE if a bitmap is present and FALSE if not. Note that text attached
to the field instead of a bitmap will return FALSE.

Usage:
   Could be used to determine whether or not to load a new bitmap.

Example:

   ' the name of the bmp picture file is the
   ' same as the string in field "title" so
   ' we can import the bmps into the memo file
   ' by cocatenating ".bmp" to the trimmed field
   ' contents
   ' -------------------------------------------
   j% = vxTop()
   If Not vxIsPicture("pic") Then
      For i& = 1 To 13 ' there are 13 recs in the file
         j% = vxGo(i&)
         ftitle$ = vxFieldTrim("type")
         fname$ = "c:\magic\bmp\" + ftitle$ + ".bmp"
         If Not vxPictureImport(fname$, "pic") Then
            MsgBox "Import Failed"
         End If
      Next i&
      j% = vxClose() ' close ensures buffers flushed
      AirPicsDbf = vxUseDbf("\vb\vxbtest\airpics.dbf")
      j% = vxSelectDbf(AirPicsDbf)
   End If  

See Also:
   vxIsMemo, vxMemoClear, vxPictureImport, vxPicturePrint, 
vxPictureRead, vxSetAlias


vxIsSubNtx
----------
Declaration:
   Declare Function vxIsSubIndex Lib "vxbase.dll" (ByVal NtxArea As Integer)
As Integer

Purpose:
   Determine whether or not the defined index is a subindex or a normal
index.

Parameters:
   NtxArea is the select area of an index file returned by vxUseNtx or
vxAreaNtx.

Returns:
   TRUE if the index is a subindex or FALSE if it is not.

Usage:
   It may be necessary to determine an update strategy or perhaps
do something based upon the record count depending on whether or not the
entire file is represented in the index. 

Example:
   If vxIsSubNtx(vxNtxCurrent()) Then
      NumRecs& = vxNumRecsSub()
   Else
      NumRecs& = vxNumRecs()
   End If
   
See Also:
   vxCreateSubNtx, vxNtxCurrent, vxNtxSubExpr, vxNumRecsSub, vxUseNtx


vxLockRetry
-----------
Declaration:
   Declare Sub vxLockRetry Lib "vxbase.dll" (ByVal ErrorMode As Integer,
ByVal WaitSeconds As Integer)

Purpose:
   Set the method of reporting a locked file or record to the user and
also specify a lock try timeout value.

Parameters:
   ErrorMode is passed as either TRUE or FALSE.

   If TRUE (the default), and an operation is performed that requires
a lock (either record or file) which is unable to be set because another
user has control of the record or file, the user is presented with a message
from vxBase that asks if he wishes to retry the operation or abort.  If 
"Retry" is chosen, vxBase attempts to set the lock again.  

   If ErrorMode is passed as FALSE, vxBase issues error code 610 "File lock
error" instead of the retry message IF vxSetErrorMethod is set to TRUE. If the
alternate error method is TRUE, the programmer can then set up his own
method of dealing with locks through the VB ON ERROR routine.  

   If vxSetErrorMethod is FALSE and ErrorMode is FALSE, the default user retry
message is sent instead.

   WaitSeconds is the number of seconds to continue to attempt setting a lock.
If zero (0), and a lock fails, the lock function returns with the error
immediately and either presents the "Retry" message to the user or triggers
the vxBase 600 error depending on the value of ErrorMode and vxSetErrorMethod.

   If WaitSeconds is greater than zero, vxBase will continue to attempt to set
the lock until WaitSeconds has expired. The maximum number of WaitSeconds that
can be specified is 32,767 (which equates to over 9 hours) and is essentially
a "wait forever" state.

Returns:
   Nothing.

Usage:
   In a multiuser environment the programmer often wishes to handle the failed
lock scenario himself rather than rely on the user to retry the lock or not. This
is the function of the errormode parameter.
  
   Setting WaitSeconds to about 20 is a good value for normal database operations.
For example, if a record is to be written, vxBase will try over and over again
for 20 seconds to set the lock. After the time has expired, the selected error
method is executed.

   If using vxBase in an unattended program, it makes good sense to set the timeout
value very high. Other processes that take control of a file for 15 or 20 minutes
then do not necessarily disrupt the unattended program from performing its tasks
after the file has been released.

   NOTE:  If a file is opened for exclusive use with vxUseDbfEX then ALL other
processes requiring that file across the entire network will be denied access to
the file.  The vxUseDbfEX function sets a network SHARE flag rather than a
Clipper style lock on the file and no one is granted access to the file no matter
what the value of vxSetLocks.

   NOTE:  vxLockRetry settings are GLOBAL to all vxBase tasks on a workstation.
Once you select a set of values, you should use the same values in all of your vxBase
programs.


Example:
   ' this function attempts to write a record and, if the required
   ' lock fails, it send the user its own message asking for a
   ' another attempt instead of using the vxBase default Retry? message
   ' ------------------------------------------------------------------
   Sub RecWrite
      Dim vxError As vxErrorStruc
      Dim RetryVal As Integer

      vxSetLocks FALSE
      vxSetErrorMethod TRUE
      vxLockRetry 0, 20
      ' will use alternate error method after
      ' retrying a lock for 20 seconds

      On Error GoTo LockError

      ' we will attempt to lock the record
      ' as long as RetryVal is zero. If the
      ' lock required by vxWrite fails, we
      ' exit to the On Error routine - which
      ' will set RetryVal to 2 if the user
      ' does not wish to retry.
      ' -------------------------------------
      RetryVal = 0

      Do
         If vxLockRecord() Then RetryVal = 1
      Loop While RetryVal = 0

      If RetryVal = 1 Then 
         If Not vxWrite() Then
            MsgBox "Record Write Error"
         End If      
      End If
      
      vxSetErrorMethod FALSE
      Exit Sub

   LockError:
      If vxErrorTest(vxError) Then
         If vxError.ErrorNum = 600 Then
            j% = MsgBox("Lock failed. Retry?", 52)
            If j% = 6 Then
               Resume Next
            Else
               RetryVal = 2
               Resume Next
            End If
         End If
      End If

   End Sub

See Also:
   vxIsRecLocked, vxLockDbf, vxLocked, vxLockRecord, vxSetLocks,
   vxUnlock, vxUseDbfEX

vxMemCompact
------------
Declaration:
   Declare Function vxMemCompact Lib "vxbase.dll" () As Long

Purpose
   Windows memory can become extremely fragmented when running a vxBase
application. The vxBase program architecture is built of many small
chunks which are all discardable and may be loaded on call. Other tasks
running concurrently with vxBase can also contribute to memory
fragmentation and consequent loss of perfromance or even out of memory
conditions when a large request is made for some fixed memory (e.g.,
reading a memo). vxMemCompact uses Windows API routines to compact
memory and leave the largest contiguous free areas possible.

Parameters
   None.

Returns
   A long integer that contains the number of bytes in the largest free
global memory object in the global heap.

Example
   ' compact memory on each return to the controlling form
   ' -----------------------------------------------------
   Sub Form_Unload (Cancel As Integer)
      vxWindowDereg(VXFORM5.hWnd)
      vxMemCompact
   End Sub


vxMemoClear
-----------
Declaration:
   Declare Function vxMemoClear Lib "vxbase.dll" (ByVal MemoFieldName
As String) As Integer

Purpose:
   Remove a memo block reference from a memo field. The bitmap OR memo
attached to the field is effectively deleted.

Parameters:
   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   TRUE if the operation was successful and FALSE if not. Always
returns FALSE is always returned if the associated dbf has been opened
as Read Only with vxUseDbfRO.

Usage:
   Delete a memo or bitmap.

Example:

   Sub ButtonDelete_Click ()
      If vxMemoClear("pic") Then
         PicBox.Picture = LoadPicture()
      Else
         MsgBox "Delete failed"
      End If

See Also:
      vxIsMemo, vxIsPicture, vxReplMemo, vxPictureImport, vxSetAlias


vxMemoPos
---------
Declaration:
   Declare Sub vxMemoPos Lib "vxbase.dll" (ByVal StartX As Integer,
ByVal StartY As Integer, ByVal xWidth As Integer, ByVal yHeight As Integer,
ByVal MemoTitle As String)

Purpose:
   Set the start position and size of an upcoming memo edit window that
will edit a memo attached to the current database with vxMemoEdit. Also
used to set up the memo edit window title.

Parameters:
   Window coordinates passed to this function use familiar character units
in the x dimension and line height units in the y dimension. The units are
converted to the average character width and height of the standard
Windows system font and are therefore device independent.

   StartX is the start position of the memo window in characters from the
left edge of the screen.

   StartY is the start position of the memo window in lines from the top
of the screen.

   xWidth is the start width of the memo window in characters.

   yHeight is the height of the memo window (including caption and menu
bars) in lines.

Returns:
   Nothing.

Usage:
   Memo window position and size are defaulted according to the size of
the parent window passed to the vxMemoEdit function if this command is
not issued. If this Sub is called, the position and size are relative to the
entire screen.

   The default memo window caption is "Memo Edit: DBF name". If this is good
enough, pass the MemoTitle as a null value (ByVal 0&).

   If you wish to set the memo title only and leave the size and position as
the default values, pass all x and y coordinates as 0. For example,
Call vxMemoPos(0,0,0,0,"My Memo Title")

   If the user sizes the memo window according to his own tastes, its position
and size will be retained on subsequent edits.

Example:
   Call vxMemoPos(10, 5, 60, 15, "Customer Complaints")
   RecNum& = vxRecNo()
   Call vxMemoEdit(VXFORM3.hWnd, "a_memo")
   j% = vxGo(RecNum&)
   j% = vxUnLock()

See Also:
   vxMemoEdit


vxMemRealloc
------------
Declaration
   Declare Function vxMemRealloc Lib "vxbase.dll" (ByVal NumDbf As Integer,
ByVal NumNtx As Integer, ByVal ReindexBuff As Integer) As Integer

Purpose
   Decrease the initial vxBase memory requirements.

Parameters
   NumDbf is the number of dbf files that will be opened simultaneously. The
minimum number is 2.

   NumNtx is the number of ntx files that will be opened simultaneously. The
minimum number is 2.

   ReindexBuff is passed as either TRUE or FALSE. If TRUE, a 64k buffer used
to speed up creation of indexes and the reindex/pack routines is set up. If
this parameter is passed as FALSE, the buffer is either removed (if is has 
already been created) or not set up at all.

Returns
   TRUE if the memory reallocation was successful and FALSE if not. 

Usage
   The first call to vxBase allocates about 160,000 bytes to track open dbf
files and open index files and also creates a 64k buffer used by vxReindex,
vxPack, and vxCreateNtx. By calling vxMemRealloc(2, 2, FALSE) this huge block
of memory may be reduced to about 35,000 bytes. If you are not going to 
be creating indexes, reindexing, or packing, the ReindexBuff may be passed
as FALSE to remove an immediate 64k.

   You should not use this function to INCREASE memory requirements. Let
vxBase handle that automatically. DBF descriptor blocks and NTX buffers
are each limited to 64k (FAR pointer arithmetic is used by vxBase) so the
maximum number of open dbf and ntx files for ALL concurrent vxBase tasks is
about 75. If more memory is required by vxBase, it will increase the size of
each dbf or ntx object by the immediate amount required (to a maximum of
64k each).

   This function should be called in your initialization routine. It should
only be called ONCE. It is not designed as an all purpose vxBase memory
manager; rather it is designed to let users with low memory situations
customize specific vxBase applications.

   WARNING: Use this function with care. This function CLOSES all open dbf
and ntx files that belong to the current task before the memory is
reallocated. If any files are open that belong to OTHER vxBase tasks,
the function fails. ALWAYS test the result for a TRUE value to ensure
the reallocation takes place.



Example

   ' The FIRST form load is used to initalize vxbase  
   ' -----------------------------------------------
   Sub Form_Load ()
      vxInit
      vxCtlGraySet
      vxSetLocks FALSE
      j% = vxCloseAll()
      If Not vxMemRealloc(2, 2, FALSE) Then
         MsgBox "Reallocation failed"
         End
      End If
   End Sub

See Also
   vxInit, vxMemCompact



vxNtxSubExpr
------------
Declaration:
   Declare Function vxNtxSubExpr Lib "vxbase.dll" (ByVal NtxArea As Integer)
As String

Purpose:
   Extract the conditional expression that controls the insertion/deletion
of keys in a subindex.

Parameters:
   NtxArea is the select area of an index file returned by vxUseNtx or
vxAreaNtx.

Returns:
   A string that contains the conditional expression used to create the
subindex. The string is either in Visual Basic format or C format depending
upon the value of vxSetString.

Usage:
   Especially useful in creating files at run time that are copies of
existing files and that are to be indexed in the same way. Or in reporting
the conditions of index insertion to the user.

Example:
   If vxIsSubNtx(vxNtxCurrent()) Then
      NumRecs& = vxNumRecsSub()
      Form1.Caption = "Subindex on " + vxNtxExpr(vxNtxCurrent()) +
" For Condition " + vxNtxSubExpr(vxNtxCurrent())
   Else
      NumRecs& = vxNumRecs()
      Form1.Caption = "Master Index on " + vxNtxExpr(vxNtxCurrent())
   End If
   
See Also:
   vxCreateSubNtx, vxIsSubNtx, vxNtxCurrent, vxNtxExpr, vxNtxSubExpr,
 vxNumRecsSub


vxNumRecsFilter
---------------
Declaration:
   Declare Function vxNumRecsFilter Lib "vxbase.dll" () As Long

Purpose:
   Return the number of records in the database that pass the defined
filter.

Parameters:
   None. The number of records returned is for the currently 
selected database.

Usage:
   Useful for generating accurate scroll bar extents and as a FOR LOOP
counter. Note that this function does exactly what you would do to
determine the number of records in a database that satisfy some
condition. It must read every record in the database, evaluate the
filter, and increment a counter. It is done at a lower level but
still can take a lot of time in a large database.

Example:
   j% = vxSelectDbf(TestDbf")
   Debug.Print vxNumRecs()
   Call vxFilter("trim(vxcountry)='CANADA')
   Debug.Print vxNumrecsFilter()

See Also:
   vxFilter, vxFilterReset, vxNumRecs, vxNumrecsSub

vxNumRecsSub
------------
Declaration:
   Declare Function vxNumRecsSub Lib "vxbase.dll" () As Long

Purpose:
   Return the number of records in a subindex.

Parameters:
   None. The subindex MUST be the currently selected index.

Usage:
   Generally used as a FOR LOOP counter or as a statistic. It may also
be used to set an accurate vertical scroll bar extent.

Example:
   If vxIsSubNtx(vxNtxCurrent()) Then
      NumRecs& = vxNumRecsSub()
      Form1.Caption = "Subindex on " + vxNtxExpr(vxNtxCurrent()) +
" For Condition " + vxNtxSubExpr(vxNtxCurrent())
   Else
      NumRecs& = vxNumRecs()
      Form1.Caption = "Master Index on " + vxNtxExpr(vxNtxCurrent())
   End If
   
See Also:
   vxCreateSubNtx, vxIsSubNtx, vxNtxCurrent, vxNtxExpr, vxNtxSubExpr


vxPictureImport
---------------
Declaration:
   Declare Function vxPictureImport Lib "vxbase.dll" (ByVal BmpFileName As
String, ByVal MemoFieldName As String) As Integer

Purpose:
   Import a bitmap from a system .BMP file into a memo field. The image
may be displayed with vxPictureRead. The maximum size of the bitmap is
16 megabytes.

Parameters:
   BmpFileName is the complete name of the bitmap file including path
and extension. Files other than bitmaps may be stored into the memo
file but they may not be read with vxPictureRead (unless they are run
length encoded compressed variants of BMPS - i.e., RLE files in either
4 or 8 bit per pixel format). The file name may be represented by a
literal string or a string variable.

   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   FALSE if the function fails and TRUE if successful. FALSE is always
returned if the associated dbf has been opened as Read Only with
vxUseDbfRO.

Usage:
   It is much more efficient both from a retrieval standpoint and from
a disk management standpoint to store bitmaps you wish to have 
associated with database records in a single source file.
   Store pictures of people in personnel files, parts images in
inventory files, homes in real estate files, etc. 

   Files other than BMPs may also be stored in a memo file. Note, however,
that only BMP or RLE format files are converted by vxPictureRead for display
in a Visual basic picture box. The memo link parameters included in the
vxCtlBrowse function will also result in bitmap display WITHOUT any
effort required by the programmer other that defining the memo window
and memo field name to the vxCtlBrowse function.

Collecting Bitmaps
   vxBase takes advantage of the rich body of functions included in Visual
Basic to handle bitmap files. Bitmaps are the Windows norm; all paint
programs, viewers, etc. can handle bitmaps - and most programs that
deal with pictures can convert foreign formats (e.g., GIF) to BMPs.
As a last resort, cut a picture into the clipboard and paste it into a 
Windows PAINT window. It can then be stored as a .BMP file. 

   Once an image is stored in a BMP file it can be transferred to the 
memo file with the vxPictureImport function. To retrieve the bitmap,
vxBase uses the standard Windows Clipboard. It puts the bitmap out to
the clipboard as a DIB (device independent bitmap). The Visual Basic
Clipboard.GetData(8) function then is used to retrieve the image
from the clipboard and display it in a VB Picture Box. The box
can have the AUTORESIZE property set to TRUE as in the sample
application if the images are all different sizes

   Bitmap files can be created from existing images you may be using in
a Visual Basic program by calling the SavePicture function. You can then
call vxPictureImport to store the image in a memo file by using the name
of the bitmap file you created with SavePicture. You can also SavePicture
to export pictures from a memo file by first reading them into a picture
box with vxPictureRead.

Example:
   ' the name of the bmp picture file is the
   ' same as the string in field "title" so
   ' we can import the bmps into the memo file
   ' by cocatenating ".bmp" to the trimmed field
   ' contents
   ' -------------------------------------------
   j% = vxTop()
   If Not vxIsPicture("pic") Then
      For i& = 1 To 13 ' there are 13 recs in the file
         j% = vxGo(i&)
         ftitle$ = vxFieldTrim("type")
         fname$ = "c:\magic\bmp\" + ftitle$ + ".bmp"
         If Not vxPictureImport(fname$, "pic") Then
            MsgBox "Import Failed"
         End If
      Next i&
      j% = vxClose() ' close ensures buffers flushed
      AirPicsDbf = vxUseDbf("\vb\vxbtest\airpics.dbf")
      j% = vxSelectDbf(AirPicsDbf)
   End If  

See Also:
   vxIsPicture, vxMemoClear, vxPicturePrint, vxPictureRead


vxPicturePrint
--------------
Declaration:
   Declare Function vxPicturePrint Lib "vxbase.dll" (ByVal MemoFieldName As
String) As Integer

Purpose:
   Print a MONOCHROME bitmap that has been stored in a vxbase memo file.

Parameters:
   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   FALSE if the function fails and TRUE if successful.

Usage:
   The bitmap image is expanded or compressed to best fit the current
page size set for the selected printer.  Color bitmaps print very
poorly because the Windows StretchBlt function used by vxPicturePrint does not
convert the color images to black and white very well.  If you are going
to print a lot of bitmaps, use a conversion program to convert color bitmaps
to black and white before saving to the memo file.

Example:
   Sub ButtonPrint_Click ()
      j% = vxSelectDbf(AirPicsDbf)
      TopRec& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GETTOPREC, 0)
      RecNum& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GETCURRENTREC, 0)
      j% = vxGo(RecNum&)
      If Not vxPicturePrint("pic") Then
         MsgBox "Print Failed"
      End If
      r& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_REFRESH, ByVal TopRec&)
   End Sub

See Also:
   vxIsPicture, vxPictureImport, vxPictureRead


vxPictureRead
-------------
Declaration:
   Declare Function vxPictureRead Lib "vxbase.dll" (ByVal PicHwnd
As Integer, ByVal MemoFieldName As String) As Integer

Purpose:
   Display a bitmap in a defined window that was stored in a memo 
file with vxPictureImport.

Parameters:
   PicHwnd is the window handle of the window that will receive the
image. In Visual basic, use vxCtlHwnd to convert a control handle to
a window handle.

   MemoFieldName is either a string variable or a literal string that
contains a valid memo field name from the currently selected database.
MemoFieldName may be qualified with a valid alias name that points to
any open database.

Returns:
   TRUE if the operation was successful and FALSE is not.

Usage:
   Only BITMAPS that have been stored with vxPictureImport may be
extracted with vxPictureRead. vxPictureRead assumes the binary object
contained in the memo is a formatted bitmap which contains a Windows
BITMAPFILEHEADER followed by a BITMAPINFOHEADER followed by an array
of RGBQUAD structures. All of this information is then followed by the
bitmap data itself. vxPictureRead creates a DIB (device independent 
bitmap) out of the Windows data structures and passes the DIB to the
clipboard, where it can easily be extracted and placed into a Visual
Basic picture box (or onto a form) with the ClipBoard.GetData(8)
function.
   If the structure contained in the memo is not a formal bitmap,
who knows what result?
 
   If you wish to store Binary Large Objects (BLOBs) in the memo file
other than bitmaps, you must use the vxBlobWrite and vxBlobRead functions
to access the data. These functions use Windows Global memory handles
as parameters and are not easily available to the Visual Basic programmer.

   NOTE: The memo link parameters included in the vxCtlBrowse function
will also result in bitmap display WITHOUT any effort required by the
programmer other than defining the memo window and memo field name to
the vxCtlBrowse function. When vxCtlBrowse displays a bitmap, it auto-
matically sizes the memo link window to the size of the bitmap. The top left
corner of your memo window is anchored. If there is not enough room on the 
form to contain the entire bitmap, it is clipped on the right and/or the
bottom to the limits of the parent form.

Example:
   The following code is a complete reproduction of the code contained
in VYFORM2 in the vxbtest project sample application:


' static switch set to TRUE in form
' load procedure so we know when this
' form is first loaded
Dim FirstTime As Integer

Sub BrowseBox_KeyDown (KeyCode As Integer, Shift As Integer)
   ' whenever a record is highlighted, this
   ' proc receives a middle button code
   ' from the ctlBrowse so we can dynamically
   ' display the picture in the memo field
   ' -------------------------------------------
   If KeyCode = 4 Then  ' middle button?
      j% = vxSelectDbf(AirPicsDbf)
      RecNum& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_GETCURRENTREC, 0)
      j% = vxGo(RecNum&)
      VYFORM2.Caption = vxFieldTrim("Title")
      If vxPictureRead(vxCtlHwnd(PicBox), "pic") Then
         ' the "8" param below is CF_DIB
         PicBox.Picture = Clipboard.GetData(8)
         ' If you want to leave the picture in
         ' the clipboard, comment out line below
         Clipboard.Clear
      Else
         PicBox.Picture = LoadPicture() ' clears the picture area
      End If
   End If

   ' -----------------------------------------------------------------
   ' NOTE: the code above is an example of using vxPictureRead.
   '       In this case (displaying records in a vxCtlBrowse table),
   '       it would be much more efficient to define the memo window
   '       and the memo field name to the vxCtlBrowse function instead
   ' -----------------------------------------------------------------
End Sub

Sub BrowseBox_KeyPress (KeyAscii As Integer)

   ' NOTE: YOU MUST ALWAYS TRAP THE ENTER KEY
   '       AND CHANGE THE KEYASCII CODE TO
   '       A ZERO WHEN USING VXCTLBROWSE
   '       EVEN IF YOU DON'T USE IT
   ' ----------------------------------------
   If KeyAscii = 13 Then
      KeyAscii = 0
      Exit Sub
   End If

   ' if ESC key is received, then emulate
   ' exit button press
   ' ------------------------------------
   If KeyAscii = 27 Then
      KeyAscii = 0
      ButtonExit_Click
      Exit Sub
   End If

End Sub

Sub ButtonExit_Click ()
   Unload VYFORM2
End Sub

Sub Form_Load ()
   ' set FirstTime switch on for Paint
   ' ---------------------------------
   FirstTime = True

   ' register the default database as the master
   ' -------------------------------------------
   AirPicsDbf = vxUseDbf("\vb\vxbtest\airpics.dbf")
   j% = vxSelectDbf(AirPicsDbf)
   
   ' first time load pictures
   j% = vxTop()

   ' the name of the bmp picture file is the
   ' same as the string in field "title" so
   ' we can import the bmps into the memo file
   ' by cocatenating ".bmp" to the trimmed field
   ' contents
   ' -------------------------------------------
   If Not vxIsPicture("pic") Then
      For i& = 1 To 13
         j% = vxGo(i&)
         ftitle$ = vxFieldTrim("type")
         fname$ = "c:\magic\bmp\" + ftitle$ + ".bmp"
         If Not vxPictureImport(fname$, "pic") Then
            MsgBox "Import Failed"
         End If
      Next i&
      j% = vxClose()
      AirPicsDbf = vxUseDbf("\vb\vxbtest\airpics.dbf")
      j% = vxSelectDbf(AirPicsDbf)
   End If
   
   ' set up the browse
   ' -----------------
   Call vxTableDeclare(VX_RED, ByVal 0&, ByVal 0&, 0, 1, 1)
   Call vxTableField(1, "Type", "type", VX_FIELD)

   Call vxBrowseCase(VX_UPPER)
   Call vxBrowseSetup(0, 0, 0, 1, "Helv", 15, VX_SEMIBOLD, 0, 0, 0, 0)
   ' If the typeface is too large on your display,
   ' CHANGE the parameter following "Helv" above to
   ' a smaller number
   ' ----------------------------------------------
   
   ' change the mouse pointer in the browse box
   ' from an I-Beam to an arrow to stop any flicker
   ' ----------------------------------------------
   BrowseBox.MousePointer = 1

End Sub

Sub Form_Paint ()
  ' register the database with this window
   ' --------------------------------------
   j% = vxSelectDbf(AirPicsDbf)

   ' make the form 3-d
   ' -----------------
   Call vxFormFrame(VYFORM2.hWnd)
   Call vxCtlStyle(BrowseBox, VX_RECESS)

   ' initiate the browse the first time only
   ' ---------------------------------------
   If FirstTime = True Then
      j% = vxCtlBrowse(vxCtlHwnd(BrowseBox), AirPicsDbf, 0, 0, 0, 0, " ")
      FirstTime = False
   End If

   ' on initial paint of the browse, middle button
   ' keydown is not sent to browse box so we want
   ' to do our dynamic display here as well as
   ' from a keydown in the browse box code
   ' ---------------------------------------------
   Call BrowseBox_KeyDown(4, 0)
  
End Sub

Sub Form_Resize ()
   VYFORM2.Refresh
End Sub

Sub Form_Unload (Cancel As Integer)
 ' close the browse
   ' ----------------
   k& = vxCtlBrowseMsg(vxCtlHwnd(BrowseBox), VXB_CLOSE, 0)

   ' close all the files
   ' -------------------
   j% = vxCloseAll()

   ' deregister the window and release memory
   ' ----------------------------------------
   vxWindowDereg (VYFORM2.hWnd)

End Sub

See Also:
   vxIsPicture, vxPictureImport, vxPicturePrint


vxSetGauge
----------
Declaration
   Declare Sub vxSetGauge Lib "vxbase.dll" (ByVal Hwnd As Integer)

Purpose
   Sets up an alternative method for generating analog or digital gauge
information on time consuming indexing and pack procedures. If 
vxSetMeters is FALSE, and a window handle representing a gauge control
(or any other valid window) is passed to vxBase via vxSetGauge, a
KeyDown event is triggered for the defined control or window whenever
the completion percentage of the active procedure changes. 
   The KeyCode parameter passed to the KeyDown event procedure contains
the percentage complete instead of a key value.  This percentage is
passed as a NEGATIVE number so the programmer can distinguish between
normal key codes and key codes sent by the vxBase procedure.

Parameters
   Hwnd is a window handle to the gauge or textbox control.  If the
form element KeyDown event being triggered is for a Visual Basic control,
use vxCtlHwnd to convert the control handle to a window handle.

Returns
   Nothing. 

Usage
   The sample below shows how to use the vxSetGauge function to control
the progress of a gauge control (the one included in the Visual Basic
Professional kit).

   The following functions will generate KeyDown events for the defined
control: vxCreateNtx, vxCreateSubNtx, vxPack, and vxReindex (note the
absence of vxTestNtx from this list).
   With vxCreateNtx and vxCreateSubNtx we are working with a single
file at a time so the absolute value of the percentage number generated
may be used to directly set the gauge control value.
   With vxPack and vxReindex, you must use a method like the one shown in
the example below to generate meaningful gauge information.
   For example, if packing a dbf file with 3 indexes and an attached
memo (dbt) file, vxBase will generate percentage progress from 0 to 100
for EACH of the 5 files involved (1 dbf, 3 ntxs, 1 dbt). If you use
a method to factor the passed percentage and also track the total progress
then the gauge information will be properly presented to the user.

Example

' This example uses a general form that contains nothing but
' a gauge control (in the form of a speedometer) to present
' analog progress information to the user. The gauge form is
' shown and set up from a PackFiles_Click menu item on the
' project's main form

' The gauge form is VXFORMG and the gauge control is generated
' by GAUGE.VBX included with the Visual Basic Professional
' toolkit. The same control is also available from MicroHelp.

' The Gauge control uses default properties EXCEPT for the
' following:
'    Name = Gauge
'    Picture = (Bitmap)  (\vb\bitmqaps\gauge\speedo.bmp)
' Style - 2-'Semi' Needle

' the following Globals are defined to enable proper multifile
' gauging during the pack operation:

Global GaugeFactor As Integer
Global GaugeTotal As Integer

' The user clicks the PackFiles menu item
' ---------------------------------------
Sub PackFiles_Click ()
   vxSetMeters False  ' turn off default meters
   VXFORMG.Show       ' show the form with the meter on it  
   VXFORMG.Caption = "Pack vxUser"  ' set the caption
   DoEvents           ' allows the bitmap to be drawn on the gauge   
   vxSetGauge vxCtlHwnd(VXFORMG.Gauge)   ' tell vxBase about the gauge
   GaugeTotal = 0     ' global total progess variable       

   ' pack user file
   ' --------------
   j% = vxAreaDbf(DirName + "vxuser.dbf")
   If j% > 0 Then
      MsgBox "vxuser in use!"
   Else
      vxClientDbf = vxUseDbf(DirName + "vxuser.dbf")
      vxWhere = vxUseNtx(DirName + "vxwhere.ntx")
      vxCl1Ntx = vxUseNtx(DirName + "vxuser.ntx")
      vxNorthNtx = vxUseNtx(DirName + "vxnorth.ntx")
      vxPhoneNtx = vxUseNtx(DirName + "vxphone.ntx")
      vxNameNtx = vxUseNtx(DirName + "vxname.ntx")
      vxCompNtx = vxUseNtx(DirName + "vxcomp.ntx")

      ' GaugeFactor is 8 (one for each file above PLUS a dbt
      ' which this file has attached
      GaugeFactor = 8
      j% = vxSelectDbf(vxClientDbf)
      j% = vxPack(VXFORM1.hWnd)
      j% = vxClose()
   End If

   ' pack fax file
   ' -------------
   VXFORMG.Caption = "Pack vxFax"  ' new caption
   VXFORMG.Gauge.Value = 0         ' reset gauge to 0
   j% = vxAreaDbf(DirName + "vxfax.dbf")
   If j% > 0 Then
      MsgBox "vxfax in use!"
   Else
      GaugeTotal = 0    ' reset total progress var
      GaugeFactor = 3   ' this file has 3 elements (dbf, ntx, dbt)
      vxFaxDbf = vxUseDbf(DirName + "vxfax.dbf")
      vxFaxNtx = vxUseNtx(DirName + "vxfax.ntx")
      j% = vxSelectDbf(vxFaxDbf)
      j% = vxPack(VXFORM1.hWnd)
      j% = vxClose()
   End If
   Unload VXFORMG   ' unload the gauge form
   vxSetGauge 0     ' turn off the gauge setting
   vxSetMeters True ' set default meters back on
End Sub
 
' This is ALL of the code associated with the generic gauge form
' --------------------------------------------------------------
Sub Form_Paint ()
   Call vxFormFrame(VXFORMG.hWnd)
End Sub

Sub Gauge_KeyDown (KeyCode As Integer, Shift As Integer)
   Dim pValue As Integer
   
   ' NOTE: --------------------------------------
   ' vxBase sends the KeyCode as a negative value
   ' so the user can distinguish between normal
   ' keydown events and those triggered by the
   ' vxSetGauge function. This is especially
   ' important if the Form KeyPreview property
   ' is set to TRUE. You can then ignore all
   ' key values that are less than 0
   ' --------------------------------------------
   If KeyCode < 0 Then
      If GaugeFactor > 0 Then
         If Abs(KeyCode) = 100 Then
            GaugeTotal = (100 / GaugeFactor) + GaugeTotal
            pValue = 0
         Else
            pValue = Abs(KeyCode) / GaugeFactor
         End If
      Else
         pValue = Abs(KeyCode)
      End If
      Gauge.Value = pValue + GaugeTotal
 
      ' ---------------------------------------------- 
      ' you could also set a digital value into a text
      ' box or label here
      ' ----------------------------------------------
   End If
End Sub

See Also
   vxCreateNtx, vxCreateSubNtx, vxPack, vxReindex, vxSetMeters

  

vxSetSelect
-----------
Declaration
   Declare Sub vxSetSelect Lib "vxbase.dll" (ByVal OnOrOff As Integer)

Purpose
   Turn off vxBase automatic database selection. Whenever a vxBase
database function is called, the last database selected for the current
window is used to perform the database function. If there was no
database active for the current window, then the last selected database
for the current task is automatically selected instead.

Parameters
   If OnOrOff is TRUE (the default), automatic database selection
according to the active window takes place whenever a vxBase function
that accesses a database is called. If FALSE, the last selection is used
without regard to window or task.

Returns
   Nothing.

Usage
   Used within Visual Basic sub functions where code attached to a
particular form does not come into play. Turning the auto select off
ensures there will be no incorrect selection going on that the
programmer is not aware of. Care must be taken when using this function
because, if the programmer allows the user to open a number of windows
each accessing a different database, the selection process may become
totally unhinged.

   vxSetSelect(FALSE) is normally used by C programmers writing DLLs or
VBXs which use vxBase calls. In a DLL, there is commonly no window that
can act as controller and even if there were, the programmer knows
exactly what database he is using and can reselect at every opportunity
to ensure the correct data comes into play.

Example
   ' sub function that does not interfere
   ' with auto selection of database in
   ' main line
   ' ------------------------------------
   Sub GetMasterNum()
      Call vxSetSelect(FALSE)
      PrevDbf% = vxSelectDbf(MasterDbf)
      MasterNum = vxInteger("masternum")
      Call vxSetSelect(TRUE)
      j% = vxSelectDbf(PrevDbf%)
   End Sub

See Also
   vxSelectDbf


vxUseDbfAgain
-------------
Declaration:
   Declare Function vxUseDbfAgain lib "vxbase.dll" (ByVal DbfName
As String) As Integer

Purpose:
   Opens a database that has already been opened IN ANOTHER AREA.
Any indexes attached to this database with vxUseNtx are also opened
in areas separate from any other instances of the same files.

See Also:
   vxUseDbf

     
vxUseDbfEX
----------
   Declare Function vxUseDbfEX lib "vxbase.dll" (ByVal DbfName
As String) As Integer

Purpose:
   Opens a database for EXCLUSIVE use. If any other user or
task is currently using the database, this function will
fail (zero is returned as the select area).

See Also:
   vxUseDbf


IMPORTANT NOTES TO EXISTING VXBASE USERS:
-----------------------------------------
   (1) If your application uses DESCENDing indexs and your current vxBase
       release is less than 2.08, these indexes MUST BE RECREATED after
       installing this release. The descending key algorithm has been
       changed to make vxBase descending keys compatible with CLIPPER
       descending keys.

       DO NOT USE DATAWORKS to recreate the indexes. It still uses the
       old algorithm. DataWorks is in the process of update.
       Use the vxReindex or vxCreateNtx functions to recreate the indexes.
  
   (2) See the VXLOAD.EXE discussion below.

Prerequisites
-------------
   vxBase is a dynamic link library of xBase functions that has been
customized for use with Microsoft Visual Basic. You must have 
Visual Basic in order to run the VB sample application. 
   If you are intending to use vxBase with another language (such as 
C), create the directory \VB before beginning installation of vxBase.
   The default installation directory is \VB, which is where
Visual Basic is normally set up. The directory that vxBase is
installed into MUST exist. If \VB does not exist, or if you wish
to install vxBase into another directory, ensure that it exists
prior to installation.

vxBase Installation
-------------------
   If INSTALL.EXE is resident on this diskette, use the
   program manager RUN command A:INSTALL to install
   vxBase. If changing the default directory from \VB,
   the directory being changed to MUST exist.

   A second sample application (project vxbtut) has been
   included starting with release 2.05 that shows you how
   to maintain a single database using vxCtlBrowse as the
   primary user interface to the database. It is installed
   in directory \vb\vxbtest along with the vxbtest project.


ZIP version
-----------
	vxBase is distributed on a single diskette or on bulletin boards
as two compressed .ZIP files. The first ZIP file is vxbdoc.zip, which
contains the documentation in a Windows Write file. This file is
essential to understanding and using vxBase. If it is missing, contact
the author at the address below.  The documentation is separated from
the rest of vxBase to allow potential users to preview it before
installing and actually using vxBase. This is especially helpful to
potential users who extract vxBase from a bulletin board. They can
evaluate the system from a documentation standpoint before committing to
downloading the larger system.

	Unzip vxbdoc.zip and view or print it. The manual is more than
250 pages long. It was formatted for an Epson 24-pin printer using
standard Courier fonts. Printed manuals may be obtained for $20.00.
See the end of the documentation for ordering information.

	The second ZIP file (vxbase.zip) contains the sample source code
and Visual Basic project files, vxbase.txt which includes all of the Visual
Basic declarations for the routines in the vxBase DLL, the vxBase DLL
itself, and VXLOAD.EXE - a Visual Basic Design Mode Utility.

	If you are going to upload vxBase to a bulletin board, it must be
sent as it was received - in two ZIP files.

	When the system ZIP file is decompressed, it contains this readme.doc
file and 3 more ZIP files. These ZIP files are:

	vxbdll.zip	the vxBase DLL and vxload.exe
	vxbtest.zip	sample source code and vxbase.txt
        vxbezy.zip      single database sample app using vxCtlBrowse
                        (project vxbtut)

	To install vxBase, first make a subdirectory under your \vb
directory named \vb\vxbtest and copy the vxbtest.zip and vxbezy.zip files
there. Unzip them and delete the zip files from your hard disk. To run the
sample applications it is essential that these files be in directory \vb\vxbtest
because this path is hard-coded into the sample code. If you MUST put them
somewhere else, you'll have to modify the file names in the source code to
reflect your location.

	Unzip vxbdll.zip and place the resulting files (VXBASE.DLL and VXLOAD.EXE)
in your \windows directory.

    To run the sample program, see the Sample Application section in the
manual. Remember to run vxload.exe before starting Visual Basic. 


VISUAL BASIC 2.0 And the Sample Applications
--------------------------------------------
	Visual Basic 2.0 or better is REQUIRED to run the sample
applications.        


Better Memory Management in Design Mode with VXLOAD.EXE
-------------------------------------------------------
NOTE: vxload.exe included with vxbase is a utility that simply
      loads vxbase.dll and runs in an iconized state. It is
      highly recommended that you run this program immediately 
      PRIOR to calling up Visual Basic in Design Mode. vxload
      controls the vxbase memory. Any crashes when testing a vxbase
      program in design mode will not affect the vxbase memory pool
      at all if vxload is running. Copy vxload.exe to your \windows
      directory and set it up as a group item next to your VB icon. 

      It is also suggested that you add the following two lines of
      code to your initialization procedure (somewhere after the call
      to vxInit()):

      Call vxSetLocks(FALSE)
      j% = vxCloseAll()

      vxSetLocks is described in the namual.

      Adding these two lines to the init procedure will close any
      files that were left open as a result of a Design Mode VB
      error. vxSetLocks will ensure that any open files left over
      from a crashed VB run will not have any leftover locks on
      your second and subsequent runs of the program while in Design
      Mode - and vxCloseAll will close any leftover files so you can
      start off with a clean slate.

      If you wish to use the default locking scheme in your finished
      .EXE, remove the vxSetLocks(FALSE) that you set up for design mode
      testing before compiling (and the vxCloseAll as well although
      that is not critical).

      If your vxBase program terminates abnormally (or you use the VB End
      menu item to terminate), and then you exit Visual Basic, an 
      attempt to close VXLOAD.EXE from the system menu that appears
      when you click on its icon will result in a "Task Sequence Closure
      Error". This is because your vxBase Visual Basic program never
      called vxDeallocate, which removes Visual Basic from the vxBase 
      task list being maintained by VXLOAD. If this happens to you,
      simply double click the VXLOAD icon to bring the VXLOAD window
      into view and select the EXIT menu item. Closing VXLOAD in this
      fashion ignores the task list.

Changes to vxBase version 2.xx
------------------------------
  (1) vxBrowseSetup corrected to display user menus if system menus
      disabled.

  (2) vxCtlStyle corrected to handle new Visual Basic 2.0 "graphical
      objects" (e.g., labels).

  (3) all SETTINGS cited as System Wide in the current documentation are
      now local to the vxBase task. These settings include the following:
          vxCtlPenWidth
          vxSetAnsi
          vxSetCollate/vxCollate collating table
          vxSetDate
          vxSetErrorCaption
          vxSetErrorMethod
          vxSetLanguage
          vxSetLocks
          vxSetMeters
          vxSetString

       If more than one vxBase task is running at the same time, the
       items set by the functions above are now local to each concurrent
       task (e.g., vxBase in French and in English can be run on the same
       machine at the same time).

   (4) inconsistent index file lockup in multiuser mode when vxSeek
       fails corrected.

   (5) DESCEND and vxDescend index algorithms changed to use 2s complement
       instead of 1s complement arithmetic to convert defined descending
       keys into the correct sequence. This makes the vxBase DESCEND
       index compatible with CLIPPER.

   (9) memo soft returns from Clipper apps are now properly stripped on
       European memos when vxSetAnsi is FALSE.

  (10) vxBrowse and vxCtlBrowse quick key displays and vertical scrolling
       speeds have been increased by a factor of 2 to 3.

  (11) memory leaks created by VB 2.0 string creation corrected by using
       new function to create Visual Basic strings if version is 2.0 or
       greater.

  (12) Max memo size now increased to 64k (was 32k).

  (13) memo reading procedures changed to read 4k blocks instead of 64k file
       chunks. This should speed memo reads and packs with memo files
       considerably.

  (14) vxAppendFrom now appends memos and bitmaps. Restriction removed.

  (15) vxGo() passed with a zero record number now returns FALSE instead
       of crashing.

  (16) vxTop now properly returns FALSE if empty file.

  (17) dbf files opened as Read Only with vxUseDbfRO no longer have their
       index files locked when positioning to a specific record.

  (18) more elegant on screen edit within a vxBrowse or vxCtlBrowse table.
       The use may accept the edit by pressing the ENTER key or cancel the
       edit by pressing ESC.

  (19) initial memory allocation requirements reduced and memory increase
       requests changed to leave new memory object attached to original
       calling task.

  (20) Dutch language support added.



Terry Orletsky
vxBase Systems
#488, 9707 - 110 Street
Edmonton, Alberta, Canada
T5K 2L9
Phone (403) 488-8100
Fax   (403) 486-8150
BBS   (403) 488-8365 up to 14400 bps v.32bis 8N1
Compuserve I.D. 70524,3723

