Help  |   Contact Us  |   About Us  |   News and Events
Books, conferences, and other information about... Moving to Linux Switching to OOo Building Linux Apps Using Visual FoxPro
Buy      Download      Your Account      Catalog      Support      Conferences      Resources      Fun

Hacker's Guide to Visual FoxPro 7.0

If you have a question about the technical contents of this book, please contact the author(s). Their email address(es) can usually be found in their bios in the About the Author section at the front of the book or on the author's bio page (click on the author's name on the book's main page.

DBF, FPT, CDX, DBC, Hike!, Pg. 28

In the section "Hip Hip Array!," the example for ASCAN() indicates that the function returns 6. In fact, in this example, with a 2x5 array, and the desired item in element (2,3), ASCAN() returns 8.

Xbase Xplained, Pg. 37

In the section "FOR Better or FOR Worse," the text states that adding a FOR or WHILE clause to a command changes its default scope to ALL. A FOR clause does give a default scope of ALL, but a WHILE clause results in a default scope of REST.


The wording of the following sentence near the end of the topic may be confusing:

In VFP 7, the BeforeRemoveTable and AfterRemoveTable events of the database fire if database events are turned on. BeforeRemoveTable fires after the Remove dialog (if you specified ?) but before the dialog warning about losing information.

The following is clearer:

In VFP 7, the BeforeRemoveTable and AfterRemoveTable events of the database fire if database events are turned on. BeforeRemoveTable fires after the Remove dialog (if you specified “?” as the table name) but before the dialog warning about losing information.


Our warning that these functions assume that any characters after the first period are part of the file extension is no longer valid. For example, the following code displays “txt”:

? JUSTEXT("C:\this is a test.dir\this is a test.text..text2.text4.txt")


In VFP 7 and later, the ALINES() function is a lot smarter than we gave it credit for. VFP 7 added the ability to specify the parsing characters that indicate a new line. It turns out that multi-character separators can be listed as well, and that separators are processed in the order listed.

Here's an example that demonstrates these features:

? ALINES(atest, x) && No surprise. Returns 2.
? ALINES(atest, x, ",") && Still no surprise. Returns 4.
? ALINES(atest, x, ",", CHR(13)) && Returns 5 - the "," followed by CR forms another item
? ALINES(atest, x, ","+CHR(13)) && Returns 2 - the only separator is the ","+CR pair
? ALINES(atest, x, ","+CHR(13), ",", CHR(13)) && Returns 4-the pair is processed first
? ALINES(atest, x, ",", CHR(13), ","+CHR(13)) && Returns 5-the comma and CR are processed separately
&& before the pair is reached.


ALTER TABLE can't handle cursors with long field names. In VFP 6 and earlier, the long fields were simply truncated. In VFP 7, any attempt to use ALTER TABLE with such a cursor results in error 1115, "Invalid operation for the cursor."

BeforeRowColChange, AfterRowColChange, RowColChange

There’s a typo in the example:

IF This.RowColumnChange >= 2

should be:

IF This.RowColChange >= 2


The explanation for the BITXOR() function with more than two parameters is incorrect. In fact, this function returns 1 for a given bit if an odd number of parameters have that bit set and 0 if an even number have it set. At first glance, that may seem like fairly odd behavior, but it makes sense if you view the ability to pass more than two parameters as shorthand for nesting multiple calls to the function. That is, this call:

q = BITXOR(x, y, z)

is equivalent to:

q = BITXOR(x, BITXOR(y, z))


This section indicates that you can treat a cursor created with CREATE CURSOR like a table. For the most part, that's true. However, the ALTER TABLE command fails if the cursor has any long field names. See the update for ALTER TABLE for the details.


FDATE() has an additional parameter, nType, that indicates whether the function returns the last modification date (pass 0 or omit the parameter) or DateTime (pass 1) of the file. The correct syntax is:

dLastDate = FDATE( cFileName [, nType ] )

This makes our complaint about not having a DateTime value obsolete. It also likely means you won’t need FTIME() anymore.


The discussion in this section indicates the _DBLCLICK system variable controls the length of time a user has to take advantage of incremental search. In fact, beginning in VFP 7, this is controlled by the new _INCSEEK variable.


These functions have an additional parameter, nScaleMode, which indicates the unit of measurement for the return value. Pass 0 or omit the parameter for foxels or specify 3 for pixels. The correct syntax is:

nYCoord = MROW( [ cWindow [, nScaleMode ] ] )
nXCoord = MCOL( [ cWindow [, nScaleMode ] ] )

The sentence “Their output is always relative to a particular window and is given in foxels” should now just be “Their output is always relative to a particular window.”


The Usage table incorrectly states that the seed using if none is passed is 10,001. The correct value is 100,001.


Our comment about REINDEX causing “CDX bloat” is no longer valid in VFP 7 and later. In addition to several other changes regarding indexing made in VFP 7, Microsoft seems to have fixed this long-standing issue.


The example in this section is incorrect. It should be:

? "The time is now " + LTRIM(STR(HOUR(DATETIME()))) + ;
" hours, " + LTRIM(STR(MINUTE(DATETIME()))) + ;
" minutes and " + LTRIM(STR(SEC(DATETIME()))) + ;
" seconds past midnight"


The rules for matching fields in a query using UNION are a little more clear-cut than the "Odds and Ends" section suggests. As stated, each query in the UNION must have the same number of fields in the list and corresponding fields must be the same type.

However, the rule used to check size depends on whether the item is an actual field name or an expression. If a field is listed, it must be the same size as the corresponding field in the first query in the UNION. An expression, though, must be no larger than the corresponding field in the first query, but may be smaller. That's why, for example, the empty string can be used as a placeholder in queries other than the first.


Our comment that “A FoxPro resource file is opened exclusively by the first user to get to it, and cannot be shared” is not valid for VFP 7 and later, since resource files can now be shared.


The StartMode property has a couple of additional values not shown in this section. The property contains 4 when checked from an APP or EXE using the runtime libraries. It contains 5 when checked from a VFP automation server compiled for multi-threaded use.


The example shown here is incorrect and may result in an infinite loop. It should be:

cFile = SYS(3)
cFile = SYS(3)


We didn’t have a lot of information available when we first wrote about this topic. However, Juergen Wondzinski (aka wOOdy) forwarded us the following information from Microsoft Technical Support.

The purpose of SYS(3052) is to avoid the “Record not available” error which occurs when a table is updated but the index or memo file has not been updated. How can this happen? VFP can lock individual records in a table, but must use file locking for indexes and memo files. To keep performance at a high level, the table write mechanism is:

lock table record
write table record
lock memo file
write memo file
lock index file
write index file

However, imagine the situation where the user was somehow able to get a record lock and write the table, and then get hung up on either the memo or the index file lock. If the user shut the machine off at this point, the memo or index would not be correctly updated.

SYS(3052) reorganizes the order:

lock table record
lock memo file
lock index file
write table record
write memo file
write index file

Which means if you ever get the “Record not available” error, and then turn off your machine, you'll no longer have written to the table.

Resource File

In the "Suggested Reading" section, the ISBN listed for 1001 Things You Wanted to Know about Visual FoxPro is incorrect. The correct ISBN is 0-9655093-3-8.