Sie sind auf Seite 1von 46

VFP Tutorial - Introduction

This short tutorial is for programmers who are considering a move to Visual FoxPro from
another programming language. The pages will lead you through the development of a very
simple database program. It only has one table and one form but the tutorial will cover the
important features of the language. Links from the main thread of the programming tutorial will
take you out to other pages covering aspects of Visual FoxPro which aren't immediately relevant
but which are useful.
Although it is simple, this application is based on a real-life example, it's an early stage of the
VFP database which we use in the office to hold details of our programming CDs. We have been
gathering CDs over the past ten years - over a thousand in all - and they're a mixture of
invaluable paid-for programs (like VFP), free utilities which might come in useful, and backup
copies of previous work. Until we built this database, we could never find the disk we wanted.
Each now has a unique ID number and they are stored on the shelf in numerical order. If ever I
need that CodeBook CD for VFP 3 again then the database tells me where to find it. The
database also holds the Serial Number and Registration Key in case we lose the original slip of
paper.
We'll start the tutorial with a description of the Visual FoxPro user interface, then we'll create a
table, describe the programming necessary to build a form that will display the data, and the
development of an executable. Links to the next six pages give step-by-step instructions:

VFP Tutorial - Development Environment


Visual FoxPro is unusual amongst the current generation of Microsoft development tools in that
it still retains a command-line interface. It has a menu system and a toolbar across the top of the
window with all the familiar buttons that you would expect but you are also faced with a
command window where you can enter FoxPro commands.

The screenshot shows part of the Visual FoxPro environment with a few lines of Fox commands
showing in the Command Window. That window is shown docked against the left-hand side of
the screen. It can float free or be docked against any edge of the screen and in real life it would
probably be wider with a smaller font size. The black pane on the right of the window is where
the results of commands are displayed.

IntelliSense
The keywords of the FoxPro language appear as upper case in blue because this is the default
setting of Visual FoxPro's Intellisense feature. As soon as Fox recognises the word that you are
typing it displays the rest of that word in blue. If you press the Space or Tab keys then Fox will
complete the word for you and follow it with a list of parameters and options that can apply to
that command. Unlike other Microsoft languages, the Visual FoxPro IntelliSense is open and
documented - it is actually a lookup into a FoxPro table - and you can add your own entries to
the list.

Using the FoxPro Command Window


When you first start to learn Visual FoxPro you might be tempted to close the Command
Window because it looks so old-fashioned and drive FoxPro in the same point-and-click style as
you would do with Access. This is possible but it is a slow and restricted way of working.

Just to take a simple example, you can create a new program file (code module) by selecting
New from the File menu and specifying that you want a new file of type Code. It is so very much
quicker though to type mc in the Command Window and hit Space or Tab. Intellisense will
expand this abbreviation to Modify Command and you can either hit Return to get a new file,
type "?" to see a list of program files, or type in the name of the file you want to open.

Advanced features of Visual FoxPro


The Visual FoxPro Command Window is very flexible. You can leave the main route through
the tutorial and go to this page to learn about some of the advanced features of the development
environment.

VFP Tutorial - Project Manager


The Visual FoxPro Project Manager controls the components of a project and lets you build then
into an executable or DLL. It also provides an easy way for you to create and modify files for
programs, forms, reports and classes. Rather than having to use the menu or the Command
Window to open a file you can just double-click on it in the Project Manager. This shortcut
applies to all types of file, not just to VFP programs. If you have added a file of type bmp to the
project then FoxPro will open Paint when you double-click on it.

Although the Project Manager


looks very like the Database Window from an older version of Access it does not hold the
program code or the design of the project components. It is in fact just a table of project
information with details of the files required, where they are stored, and any comments you want
to associate with them. This means that many database projects can share the same files of
common procedures or class libraries.

Create a new project by typing CREATE PROJ in the Command Window:


This shows an empty project. As files are added to the project the nodes on the TreeView will
expand. As an example, the Data node will expand to show 'Databases', 'Free Tables' and
'Queries'. Each of the main nodes of the tree has its own tab and if you wanted to concentrate
forms and reports then you could see them on the 'Documents' tab.
There are six buttons on the right of the Project Manager. The first three let you create a new file,
add an existing file to the project, and modify one of the files from the project. The Run button
will execute a program file, display a form file, or print a report file. Remove removes the file's
reference from the project and Build will build the project files into a DLL or executable.

Using the Project Manager


The first thing to do with the Project Manager is to get it out of the way. If you click on the title
bar then you can drag it up onto the main menu and dock it clear of the desktop area. Click on a
tab to drop down a list when you need one of the files. This saves a lot of space on the desktop.

The screenshot shows the Project Manager docked with the documents tab expanded to show
that there are two forms in this project. The mycd form is shown in bold because this is the main
form in the project, the one that will appear when the executable runs. Note that, unlike in
Microsoft Access, you do not have to have a form as the main component of the project. In fact it
is more normal to start with a program that sets up the correct environment and displays a menu.

None of the buttons from the full display are visible when the Project Manager is docked like
this but all their functions are available on a right-click menu.
If you do want to able to keep one of the pages visible whilst the Project Manager is docked then
you can tear that tag off. Just click on its caption and drag it onto the FoxPro desktop. A close
widget will appear on the tab. Click that to close the floating tag and return it to the docked
position.

VFP Tutorial - Data Tables


Table files
Unlike Access or SQL Server, FoxPro stores all the tables of its database as separate files. Fields
of fixed-length data are held in a file with an extension of .dbf (database file); the variable-length
data, graphics and OLE objects have an extension of .fpt (foxpro text and the indexes are .cdx
(compound index. This separation has good and bad points but is proved reliable over many
years.

Designing a table
We will skip the first and most important phase of this process and assume that the structure of
the table has already been considered. This project has a single table named CD with the
following structure:
Field

Type

Size

Description

CDID

Unique sequential number to identify each CD

Publisher

30

Publisher of this CD - eg 'Microsoft'

CDName

30

Name of this CD - eg 'Visual FoxPro 8'

SerialNo

40

Manufacturer's serial number

Key

40

Security Key

CDDate

Date received

Creating a table
Click on the Data tab of the Project Manager then right-click on Free Tables. This simple
application will only have a single table and does not need the overhead of a database.
Select New File then New Table from the dialog that appears. This dialog allows you to start the
Table Wizard which can be useful if your application matches one of the templates provided.
An explorer dialog will appear offering to create a table named 'Table1.dbf'. Change the name to
'CD.dbf' and save it in the same folder as the project manager file. A real life project typically
has its files in a directory tree structure but we'll put all the files in the same folder here for
simplicity.
The Table Designer will appear. Add the six fields from the list above and click OK when you
have finished. Note that no size was requested for the Integer and Date fields, the size of these
data types is fixed by FoxPro.

The greyed-out fields on the right of the designer are only available for tables which are part of a
database. You can leave the main route through the tutorial and go to this page to learn about
Visual FoxPro databases.

Viewing the table


When you have closed the Table Designer you should see an entry like this in the status bar at
the base of the screen:

This shows that the table named 'CD' is open, it's open for your exclusive use, it holds three
records and the record pointer is on the first record.
Type:
Browse

in the Command Window to view the table.


Do not worry if the status bar is empty. If there is no table open when you type the command
then Fox will display a directory tree and ask you to select a table.

Adding some records


Unlike Access, you cannot just create a new record by typing on a blank line in the grid. You
have to select Append New Record from the Table menu. This menu pad appears whenever a
Browse window is open on the desktop.

Do this three or four times and add some data to the table so that you will have something to
work with when you design a form.

VFP Tutorial - Form Designer


As with any other Windows development tool, the form is the basic interface for the user in
Visual FoxPro.
FoxPro has a Form Wizard which will produce a good-looking form very quickly but the design
relies on a number of complex class libraries and is difficult to understand or modify. We will
build a straightforward form by hand.

Create a form
Click on the Documents tab of the Project Manager then right-click on Forms. Select New File
then New Form from the dialog.
The Form Designer will appear:

The screen shot shows the Form Designer and the Form Controls toolbar with the mouse
positioned above the Button control so that its tooltip is displayed.

Add data
The form has to be connected to a data table. Right-click on the form and select Data
Environment .... A directory tree will open so that you can select a table. Click on CD.dbf then
close the Add Table dialog. This should leave you with the form and the Data Environment
windows visible:

Use the mouse to select the six fields from the Data Environment and drag them to the form. If
you do this with a normal left-click then FoxPro will automatically create a grid control for the
fields. Start the drag with a right-click instead. Note that the tooltip will show you the size and
type of the field as you select it.
When you drop the files a menu will appear with the option of showing the fields as a grid or as
multiple controls. Select the Create Multiple Controls Here option. Make sure that you move the
mouse to the top-left corner of the form before you drop the fields. Some of the fields are quite
wide and you might have to make the form a bit larger to accept them it. Just click on the form
border and drag it to the size you want.
Close the Data Environment and leave the Form Designer on screen.

Run the form

There are three ways of running the


form. You can:

Click the red exclamation mark on the toolbar


SelectRun Form from the Form menu
Use the keyboard shortcut CTRL+E

You will be asked to save the form before you can run it. FoxPro will suggest a name something
like 'Form1.Scx'. Change this to 'MyCD.scx' or something more suitable but do not change the
file extension. Form data in Visual FoxPro is stored in a pair of files with 'scx' and 'sct'
extensions. The 'scx' file is actually in VFP dbf format and the 'sct' file holds its memo fields in
fpt format.
Note that the file name is not the same as the form name. The form name is a property of the
form.

Moving and adjusting the size of controls


The obvious way to do this is to drag with the mouse and this is the fastest technique for making
crude adjustments. Use the cursor keys for fine adjustments. Each key will nudge the control one
pixel in the appropriate direction. Hold down shift and use the cursor keys to stretch or shrink the
control by one pixel at a time.
The Format menu has options to align and size groups of controls. You can select multiple
controls by shift-clicking on the controls one-by-one or by dragging a selection marquee around
the group of controls. The selection marquee does not have to surround a control, it will select
any control that it touches.

Improve the appearance of the form


The form will appear on screen and show the first record in the table but that's all that it will do.
It also needs a lot of work on its cosmetic appearance. The captions are all at default values and

the colour is just the basic Microsoft grey. All these can be improved by altering the properties of
the form and controls. Properties are covered in the next page.

VFP Tutorial - Navigation


All the basic controls are available on the Form Controls toolbar. This is shown docked above
the Form Designer but can be dragged or docked anywhere on the desktop.
The FoxPro toolbar looks familiar but there are subtle differences between it and the equivalent
toolbars in Access and Visual Basic. To add a control to the form you click once on the toolbar
then once on the form. This will add the control to the form at its default size. You can click on
the toolbar then click on the form and drag the control to a new size but it's easier to get the
control onto the form in one operation and adjust the size later.
Don't try to drag a control from the toolbar to the form. Nothing will happen.

Add a Close button


Click on the button control (fifth button from the left) on the toolbar and drop it on the bottom
right of the form. Double-click on the button to open an editor on the code that will run when the
button is clicked. Type this line of code into that window:
ThisForm.Release

ThisForm is the FoxPro equivalent of Me in Access and refers to the form which holds this
object. As you type the period a list of possible methods will appear. By the time that you have
typed 'rel' Fox will have identified that you want the Release method and will pop up a tooltip to
identify it. Press Enter to confirm.

Close and save the code window by pressing CTRL+W or by clicking the Save button on the
toolbar. Then press CTRL+E or the exclamation mark on the toolbar to run the form.

Click the button and the form will close and return you to the Form Designer. The caption on the
button is not quite right and we will correct this by changing the Caption property of the button.
Right-click on the button and select Properties... from the menu.

Control properties
FoxPro is a flexible object-oriented system with a wide range of properties. You can reduce the
number displayed so that you only see those which have been changed from their default values.
Right-click on the name 'Command1' at the top of the Properties Window and select Non-Default
Properties Only from the menu. This will filter the list to just the seven properties shown.

Click on the Caption property and type Close as a new value. Note that you cannot type where
the value is shown in the list, you have to type the new value of the property into the textbox
above.

Whilst you are in the Properties Window you can also change the name of the control from its
default value of "Command1" to something more informative. You can see amongst the
properties that the Click event holds a 'User Procedure'. This code is part of the object and will
still be a part of the object if you change the object's name. Visual FoxPro does not suffer from
the problem that Access and Basic have where changing the name of a property breaks the link
to its methods and leaves you with an orphan.

Navigation buttons
Follow the same technique to add two more buttons to the form and change their Caption
properties to read 'Prev' and 'Next'. Double-click on the 'Prev' button and type this code into its
Click event:
* Move to the previous record and refresh the form
Skip -1
ThisForm.Refresh

The code in green is a comment. If a line starts with an asterisk then everything on that line
becomes a comment and is ignored by the compiler.
Close the edit window, double-click on the 'Next' button and type this very similar code into its
Click event:

* Move to the next record and refresh the form


Skip 1
ThisForm.Refresh

Add two more buttons to go to the first and the last record. The FoxPro commands are:
* Move to the first record and refresh the form
Go Top
ThisForm.Refresh

and
* Move to the last record and refresh the form
Go Bottom
ThisForm.Refresh

These four buttons are so similar that we would be thinking about subclassing them all from the
same source in a real system.

Run the form


Click the red exclamation mark on the toolbar or select Run Form from the Form menu.

Improve the navigation

VFP Tutorial - Program Code


The Visual FoxPro language uses the same syntax in programs, functions and methods as it does
in the interactive Command Window.

Prev button
This button will move us to the previous record in the table so we must make sure that the user
cannot try to navigate beyond the first record. An If statement in the click method of the Prev
button will detect whether we are trying to move to the record before the first one and this code
will prevent the user seeing an error message.
It uses the BOF() function to determine whether we are at "Beginning of File":
* Prevent the Prev button going too far
If Bof() Then
* Do nothing - we are already on the first record
Else
* Skip to the previous record
Skip -1
EndIf

The Then in the first line is optional. Anybody who works in Visual Basic as well as in FoxPro
will already be in the habit of adding it because it's compulsory in that family of languages. The
final EndIf is one word. You will get a syntax error if you use two words in VB style End If.
The Else clause is optional but the components of the If structure must always be on separate
lines.

Next button
The Next button needs to detect whether we are at "End of File" to prevent the user moving
beyond the last record. It has similar code using the EOF() function but the logic has to be more
complex because the EOF() function does not become true until after the record pointer has
moved beyond the last record.
* Prevent the Next button pushing us off the end of
* the data
If Eof() Then
* We've already fallen off - go to the last record
Go Bottom
Else
* Skip to the next record

Skip 1
* Has this move made us fall off?
If Eof() Then
* We have fallen off - go to the last record
Go Bottom
Else
* Do nothing - we're safe
EndIf
EndIf

Enabling buttons
Preventing the user from seeing these error messages improves the usability of the form. Another
improvement would be to set the Enabled property of the Next and Last buttons false when we
are on the last record. This will grey out the buttons to make it obvious that the user cannot move
any further in that direction.
ThisForm.cmdNext.Enabled = .F.
ThisForm.cmdLast.Enabled = .F.

We will need similar commands to disable the Prev and First buttons when on the first record.
Note that you have to give the full names of the buttons. They have no independent existence so
you must specify them completely.
True and False values are represented by .T. and .F. in FoxPro. They are a separate logical data
type and are not related to integers in any way. FoxPro uses .Null. to represent a null value in any
data type.

VFP Tutorial - Variables


FoxPro is very flexible in its use of variables. It does not insist that a variable be declared before
it is used and it does not regulate the data type stored in a variable. It is however good practice to
declare a variable at the head of a program and maintenance becomes very difficult if you change
the data type stored in a variable.

Scope of variables
Visual FoxPro has three levels of scope for variables. These are declared by the Local, Private or
Public keywords. Variables can be declared anywhere in code before the point where they are
first used but the best place to declare them all is at the start of the program or module.

Public variables
A public variable is available to all code in the program. Any statement anywhere is able to
modify its value so a bug involving a public variable can be very difficult to track down. Despite
that danger, a few carefully chosen public variables can simplify a program design. If you
declare the user's ID as public:
public glUserID

then you can read the value at login and be able to use that value everywhere else in the program.
That's a useful facility as long as the value of the variable is only ever set in one place.
One other danger with public variables is that they persist in the development environment after
the program has finished executing. It is not unknown for a program to run successfully on the
developer's PC and to fail on a user's PC because it relied on the continuing existence of a public
variable left over in the development environment from previous run of the program.

Private variables
Private variables are something of a hangover from early versions of FoxPro where they were the
only alternative to a public variable. A private variable is available in the program where it is
declared and in all programs which are called from that program. The scope of the variable is
limited to some extent so it is slightly safer than a public variable. This was the only alternative
available in versions 1 and 2 of FoxPro but is rarely used in Visual FoxPro.
If the customer's name is declared as:
private pcCustomer

then all the routines called from this program would have access to that variable. Some
developers would take advantage of this availability to avoid having to pass the value across as a
parameter.
If a variable is not declared before it is used then it is created with a default private scope.

Local variables
Local variables were introduced with the launch of Visual FoxPro as FoxPro version 3. As their
name suggests, a local variable is only available in the program in which it is declared. If you
declare a variable such as:
local lnCount

then you know that nothing outside of that program can read or change the value of lnCount.
Debugging becomes much easier and for this reason, most variables used within a program will
be declared as local.

Variable names
Variable names can consist of any combination of letters, numbers and underscores and are not
case-sensitive. The name must start with a letter or underscore.
Names can be up to 128 characters long in Visual FoxPro. Be careful when working with version
2.6 or anything earlier because only the first ten characters of a name were significant. If you had
two variables named lnTimeForPainting and lnTimeForPreparation then FoxPro would treat
them both as the same variable with the ten-letter name lnTimeForP. The program will run and
give answers that are nearly, but not quite, correct.
You have to be very careful when writing FoxPro programs. You might declare a local variable
named lnPrice but if you make a typing mistake later on and store a value in a variable named
lnPrce then FoxPro will leave your original lnPrice unchanged and will create a new private
variable named lnPrce to hold the value.

Naming convention
Microsoft have supported a simple naming convention for FoxPro variables. Each name has a
two-character prefix. The first letter of the prefix describes the scope of the variable, the second
letter describes the variable type:
Scope

Type

g Public - or global a Array


p Private

c Text - or character)

l Local

d Date

t Parameter

l Logical
n Numeric
o Object
t Datetime
y Currency

Note that these conventions are purely for the convenience of the programmer. FoxPro does not
analyse the prefix. The program will compile and run successfully even if you give a misleading
name such as ldBirthday to a public variable holding the user's logon name.

Variables with an m. prefix


It is permissible to have a variable with the same name as a field in the current table. If this
conflict occurs then FoxPro will always take the value from the field. Use the m. prefix if you
need to refer to the memory variable.
This prefix was very common in FoxPro 2.6 and earlier because the Scatter and Gather
commands were used to copy values between fields and variables of the same name. These
versions of FoxPro lacked buffered data entry so the technique was to scatter the values from
fields to variables, allow the user to alter the value of the variables and then gather values from
variables to fields if the record could be locked.

VFP Tutorial - Program control


FoxPro is a structured language without a GoTo statement. Program flow is controlled by
selection and repetition structures:

Selection
Selection structures determine whether the program should execute one section of code or
another. The FoxPro syntax supports two ways of making this choice:

If
Do Case

Repetition
Repetition structures determine how many times the program should execute a particular section
of code. FoxPro supports three types of repetition:

For ... Next


Do While
Scan

VFP Tutorial - If ... Then ... EndIf


Allows a choice between two actions depending on the value of a logical expression:

If _TALLY = 0 Then
Wait Window 'No records found'
Else
Copy To TmpFile.xls Type XLS
Wait Window 'Exported to Xls'
Endif

If the expression _TALLY=0 evaluates as true (.T. in FoxPro) then the statements between If and
Else will be executed.
If the expression evaluates as false (.F. in FoxPro) then the statements between Else and EndIf
will be executed.

Notes
_TALLY is a variable maintained by FoxPro which holds the number of records processed by
the last command.
The condition must evaluate as .T. or .F. because the logical values in FoxPro are a separate data
type and an integer result will not be interpreted as a logical value.
The Then is optional but does no harm. If you are used to working in the VB family of languages
where the word is compulsory then you will probably be in the habit of adding it automatically.
The keyword EndIf is a single word. If you switch between using VB, Access and FoxPro then
you will continually be making the mistake of writing it as two words.
The Else clause is optional and the structure can just consist of If ... EndIf.
The components of the structure must be on separate lines.
There is no ElseIf clause. Use a Do Case structure when you want to select between more than
two choices.
Back to FoxPro program control .

VFP Tutorial - Do Case


The syntax of the Do Case structure in FoxPro allows a choice between several actions based on
the result of various logical expressions:

Do Case
Case _TALLY = 0
Wait Window 'No records found'
Case _TALLY = 1
Wait Window 'One record found'
Otherwise
Wait Window 'Many records found'
EndCase

Each Case statement is followed by an expression which must evaluate to true or false. FoxPro
evaluates each of these in sequence.
If the expression following the first Case statement evaluates as true (.T. in FoxPro) then the
statements between this Case and the next one will be executed. The rest of the structure will be
skipped and execution will continue on the line following the EndCase statement.
If the first expression evaluates as false (.F. in FoxPro) then the next Case statements will be
evaluated in turn until one is found to be true. If none are found to be true then the code
following Otherwise will be executed.

Notes
_TALLY is a variable maintained by FoxPro which holds the number of records processed by
the last command. It is very useful in situations like this where you need to know how many
records have been found.
Each logical condition must evaluate as either .T. or .F. because the logical values in FoxPro are
a separate data type. Unlike in many other languages, an integer result will not be interpreted as a
logical value.
Be careful to get the tests in the right order when designing a Case structure. Remember that the
expressions are evaluated in sequence and put the toughest test first. If for example you need to
test whether something is greater than 1 or greater than 10 then you must test for greater than 10
first. If you test for greater than 1 first then a value such as 11 would pass that test and the greater
than 10 test would never be reached. This sort of mistake can be difficult to detect in tests
because the program runs without error and will give the right result most of the time.
The Otherwise clause is optional. If it is not included and all the individual Case statements
evaluate as false then none of the code will be executed.
It is good practice to include an Otherwise clause even if there is no action which needs to be
taken. If you are positive that the individual Case statements cover every possible situation then
add an Otherwise and display an error message.

Each Case can have an expression based on a different variable. This example works out the
method of delivery from the value of the order, the weight of the goods and the country to which
it has to be delivered.
Do Case
Case lyCost > 1000
*-- Free delivery for large orders
lcDelMethod = 'Free'
Case lnWeight > 10
*-- Buyers must collect cheap, heavy orders
lcDelMethod = 'Collect'
Case lcCountry <> 'UK'
*-- Airmail for a light, cheap, overseas delivery
lcDelMethod = 'Airmail'
Otherwise
*-- Must be light, cheap, inland delivery
lcDelMethod = '2nd class mail'
EndCase

VFP Tutorial - For ... Next loop


Executes a section of code several times. The number of repetitions is controlled by a counter
which increases by one each time that the loop executes:
lnLimit = 10
For lnCount = 1 To lnLimit
* Print the numbers from 1 to lnLimit inclusive
Print lnCount
Next lnCount

The code in this example will execute ten times and will print the numbers from one to ten.

Notes
The Next lnCount marking the end of the structure can be replaced by EndFor but you may find
it easier to use the Next option because it is the same form as in Visual Basic and Access.

VFP Tutorial - Do ... While loop

Executes a section of code several times (zero, one or many times) whilst an expression remains
true. This example will keep keep adding to a total until that total reaches 100;
lnLimit = 100
lnTotal = 0
Do While lnTotal < lnLimit
*-- Keep adding until we hit the limit
lnTotal = lnTotal + lnNextItem
Print lnTotal
EndDo

If the expression lnTotal < lnLimit evaluates as true (.T. in FoxPro) then the statements in the
loop will be executed and the expression will be evaluated again. The loop will continue until the
expression evaluates as false (.F. in FoxPro).
If the expression evaluates as false when FoxPro first reaches it then the statements inside the
body of the loop will never execute.
The code in this example will keep adding new items until the total exceeds the limit.

Notes
The test condition must evaluate as .T. or .F. because the logical values in FoxPro are a separate
data type and an integer result will not be interpreted as a logical value.
This is the only form of the while loop in Foxpro. There is not an alternative form with the
expression being tested at the end of the loop and there is not an inverted form which runs until
the expression evaluates as true.

VFP Tutorial - Scan ... EndScan loop


The scan loop is unique to FoxPro. It processes records in a table and executes the commands
within the loop once for every record in the current work area:
* The staff table holds managers and employees
Use Staff In 0
* Modify salaries and bonuses
Scan
If Title = 'manager'
* More money for managers
Replace Salary With Salary * 1.10
Replace Bonus With 10000

Else
* No rise or bonus for the other employees
Replace Bonus With 0
EndIf
EndScan

The code in this example will modify every record in the Staff table and reward the managers.

Notes
This example shows how one control structure can be embedded within another. The If structure
is executed once for every record in the table.

The FoxPro GOTO statement


FoxPro does in fact have a GoTo statement but it's not a program control command. Instead it
moves the record pointer to the record number specified:
Goto 12
will move the record pointer to record number 12. This command is useful in small record sets
but can be slow in a large table and it goes against the spirit of a relational database. When you
use it you assume that you can rely on the absolute position of a record in a data set and you
restrict yourself to using native FoxPro data sources.
This command should be considered as being included for backwards compatibilty only.
The word "Goto" is actually optional. The command:
12
on its own will move the record pointer to record 12. An idiosyncracy of the language which
should not be used in production code.

VFP Tutorial - Build an Executable

The last stage in the tutorial is to


build an executable. For this step we need the FoxPro Project Manager back on the screen. If you
are very careful with the mouse then you can drag the Manager off the toolbar but it is very easy
to drag a single tab instead of the whole manager. Being able to drag a tab off the toolbar is a
useful feature during form design but it's not what we want to do at this stage. The easiest way to
undock the Project Manager is to right-click on the docked manager and select Undock from the
menu that appears.
Click the Build... button to display the Build options.

Build Options
The standard version of Visual FoxPro lets you build executables and DLLs which can be freely
distributed without paying additional licence fees. Select the Win32 Executable option and select
the Display Errors tick box. Then click OK to build the executable.

You will be asked for the name of the


executable. The default is for the executable to have the same name as the project and to be in
the same directory but you can override both these options.
If you have Set Safety On and the project has been built before then you will be asked whether
you want to overwrite the existing file.
The FoxPro development environment is not a verbose one. The cursor will change to an
hourglass when the build starts and you may see progress messages flickering in the Status Bar
as the build proceeds but that is all that will happen. There will be no message to say that the
build has succeeded. If the cursor returns to normal without there having been any error
messages then the build will have succeeded.

Running the executable


You can run the executable from within the FoxPro development environment by selecting Do
from the Program menu or by typing Do Cd.Exe from the Command Window.
If you try to run the executable from outside the development environment then you will find
that it just flashes on the screen and then disappears. This is because Visual Foxpro is eventdriven. We need to start the event-processing loop to tell FoxPro to start looking for mouse and
keyboard events as soon as the form is displayed.
Open the form from the Project Manager and double-click on the surface of the form itself. An
edit window for the Load event of the form will open. We want to put some code into the
Activate event so click on the combo box showing 'Load' and pick 'Activate' from the list of
events. Type the following code into the edit window for the Activate event:
Read Events

This will start the event processing loop but we now need to stop the loop when the form closes.
Double-click on the Close button and change the program code in its Click event to read:

Thisform.Release()
Clear Events

Save and close the form and use the Project Manager to build the executable again. You should
now be able to close FoxPro altogether, navigate to the executable in Windows Explorer, and run
the executable by double-clicking on it.
The site has more details on stopping and starting the event-handling loop.

Distributing a FoxPro executable


There are two ways of distributing a FoxPro application and both are beyond the scope of this
tutorial. One is to use the Setup Wizard (or InstallShield Express in later versions). The other is
to just copy the files required to the user's PC. The files are listed in the FoxPro help system (and
on this site at foxfiles.html). Copy them all to the same folder as the executable program. A
FoxPro executable does not use the same DLLs as any other Micosoft applications so
distribution is usually very straightforward.
FoxPro distribution requires no royalties. Once you have built your executable you can distribute
as many copies of the program as you like. There is no limit on the number of people who can
use it and no per-seat licencing required for the users. This ease of distribution makes FoxPro a
very effective tool for building custom databases.

Cannot quit Visual FoxPro

The 'Cannot Quit Visual FoxPro' error message must be one of


the most common problems new developers meet when starting to work with Visual FoxPro.
It has been with us since the launch of Visual FoxPro 3 but the problem still causes difficulties.
The error message does not give you an error number so you cannot find it in the VFP Help
system. Help also returns nothing if you search for 'Cannot Quit Visual FoxPro' and the online
help at MSDN is equally unhelpful. A search on Google though will show you that it's a very
common question in all the FoxPro support forums so it's disappointing that Microsoft have not
added it to their own Help documentation.
Especially as it is a very simple problem to fix.

Close the application


The first thing to do is to close the application that has locked. The least damaging way of doing
this is to use the Windows Task Manager. In Windows 2000 and Windows XP you can open the
Task Manager by pressing Ctrl+Alt+Del or by right-clicking on the Windows status bar. Select
Task Manager from the options that appear then click the Applications on the Task Manager
dialog:

Select your Visual FoxPro application from the list then click the End task button. You will be
warned that this is an extreme act and asked to confirm that you do indeed want to cancel this
process. Click OK and wait. Windows may take several seconds to complete the task of closing
down the application. When it has been closed you will be told that you have terminated FoxPro
prematurely and asked whether you want to report the problem to Microsoft. We have been
reporting this for ten years now so I suspect it will be a waste of time to report it again.
Now that you have cancelled the application, close the Task Manager and open your project up
again in FoxPro.

Solution
The problem arises because Visual FoxPro is event-driven. The RunTime engine opens your
executable and then responds to events as they occur. You have closed your application but not
told FoxPro to stop waiting for events.
The command to stop the event-processing loop is:
Clear Events

and FoxPro must execute this command whichever way that the application closes down.
Depending on the structure of your application you might put the command is several different
places:

In the procedure called by the Quit option on the File menu.


In the Click event of the button that closes your main form.
When the application shuts down:
On Shutdown Clear Events

FoxPro executable flashes on screen and vanishes


The other problem you'll hit with the Visual FoxPro event-processing loop is when you find that
your executable won't run outside of the development environment. You just see a flash of your
main form on screen before the executable closes. This too is tied up with the event-processing
loop. More details here.

FoxPro form flashes on the screen and


vanishes
Everybody meets this problem with their first Visual FoxPro executable; the program runs well
in the development environment but fails when run as a stand-alone executable from Windows.
The FoxPro window just flashes on the screen and then vanishes. You can search VFP Help for
terms like "flash", "vanish" and "disappear" but you will find nothing. The information is hidden
away under "How to: Control the Event Loop" and you won't be able to ship your exe until you
find it.
This problem crops up because Visual FoxPro is now an event-driven language. It runs through
the code for your form, reaches the end, and the program terminates when there is nothing more
for it to do. Everything vanishes from the screen. The same thing will happen if your application
is based on a main menu; FoxPro will run through the code to create the menu, the menu will
flash on the screen but then the program terminates and the menu vanishes.
The solution is a simple one once you realise what FoxPro is doing. You have to tell VFP to start
its event-processing loops. The command that does this is:
Read Events

You'll need to add this code in different places depending on whether you are using a form, a
menu or a program as the main element of your application.

If you are using a form then add this as the last line in the Activate event. This will allow the
form to load and initialise itself before going into the event processing loop and waiting for
mouse and keyboard events.
In a menu, add it to the CleanUp code snippet. Select General Options from the View menu then
click the Cleanup... tick box. An edit window will open behind the dialog; click OK to close the
dialog window and the CleanUp edit window will remain:

If you have a program as the main element of your project then add the Read Events line
immediately after you have set up the user interface by loading a form or menu. Fox will then
stop executing this sequential code and will start monitoring keyboard and mouse events, waiting
to see what it should do next.

One last thing to remember

This will start the event processing loop but we need to stop the
loop in order to close the application. If you forget to do this then you'll hit the second mostcommon problem - the "Cannot quit Visual FoxPro." message.

You avoid this by using the Clear Events command to stop the event-processing loop. Execution
will then continue from the line following the Read Events command in the main program.

VFP Tutorial - More about the environment


The FoxPro Command Window is something like the Immediate Window in a Microsoft Access
database. The most obvious difference is that the results of your commands will appear on the
FoxPro desktop rather than in the Command Window itself. The other difference is that the
contents of the Command Window persist from one session to the next. It may seem a small
point but when you fire up Fox on a Monday morning you can see what you were doing on
Friday and it's easy to carry on.
The Command Window is a specialised instance of the FoxPro editor. This means that you can
drag and drop between the Command Window and code windows. You can test a snippet of code
interactively before dragging it into your program or pull a line of code from a program and
experiment with it in the Command Window.
If you drag the Command Window to the side of the screen and dock it then it will never be
covered by other FoxPro windows. If you choose to have the window floating on the screen then
it may disappear. Press Ctrl+F2 to bring it to the fron again. This will also restore the window if
you have accidentally closed it.

Entering and re-entering commands


The basic technique is to type a command in the Command Window and press Enter to execute
it. You can re-execute any command by moving the cursor to any position in that line of the
Command Window and pressing Enter again. You can also edit the existing line before
executing it.
This is a reassuring feature when you are manipulating data from the Command Window. If for
example you need to delete all the records of customers from the USA then you can approach the
problem step by step and build confidence before you actually delete the records.
Start by typing something like:
browse for country='USA'

to see all the customers in the USA. If you are convinced that your selection is correct then you
can take the cursor back up to that line and change the first word so that the command becomes:
delete for country='USA'

You have made no change to the selection criterion so you can be certain that you will be
deleting the correct set of records. If you wanted even more reassurance, you could have edited
the command to read:
copy to USAList type Xls for country='USA'

and exported a list of the records that are about to be deleted into an Excel spreadsheet. Many
FoxPro commands share a similar syntax and you can save a lot of time and typing by just
modifying earlier entries in the Command Window.

SQL
The example above used traditional dBase commands but Visual FoxPro also accepts SQL
commands natively. You can type a command like:
select cust_id, company, country ;
from customer ;
where country='USA' ;
into cursor csrUSA

into a program or into the Command Window and select the name and ID of all the USA
customers into a temporary table. This SQL capability means that FoxPro databases can easily be
upgraded to run on larger systems such as SQL Server, MySQL, or Oracle servers. SQL is also
very useful for populating listboxes and combo boxes as a form loads.
Note that the semi-colons here are nothing to do with the syntax of SQL. The semi-colon is the
FoxPro line-continuation character and indicates that this is really a single command.

Help
Press F1 or type help to open the Help system.
FoxPro is a self-contained language. Although it does integrate well with the rest of the
Microsoft family you do not need to call on such things as ADO or Common Control DLLs or
.Net in order to write a FoxPro system. The Help system is also self-contained and loads quickly
because it is a single chm file.
FoxPro comes with a sample database of customers, invoices and stock tables in C:\Program
Files\Microsoft Visual FoxPro 9\Samples\Data or in the equivalent folder on earlier versions of
Visual FoxPro. This is only a small database with a few hundred records but it is a useful
resource when you are learning. It is wise to copy the entire folder to your own folder before
starting to use it so that you retain a clean copy of the original data.
Another useful resource supplied with Visual FoxPro is the Solutions application:

The Solutions application consists of perhaps a hundred small forms and programs which
demonstrate useful techniques. These are supplied with their complete source code and a
dedicated help file to explain the techniques that have been used. Select Do from the Program
menu then navigate to the C:\Program Files\Microsoft Visual FoxPro 9\Samples\Solution folder
and run Solutions.App.
Early versions of Visual FoxPro shipped as part of the Visual Studio suite and with these you
will find the application in the MSDN folder.

IntelliSense in Visual FoxPro


IntelliSense was advertised as something that would bring VFP up to the level of Visual Basic
but in typical FoxPro fashion the team went one better.
IntelliSense provides a variety of services but I particularly like the way that we can add our own
entries to the FoxCode table. As an example, if I type CB in a program now I get:
*-- |
*-- Changed by Geoff Franklin - 23/06/09

where the date is inserted automatically and the cursor is positioned one space to the right of the
'*--' on the first line, ready for me to type my comments into the program. It's a big help when
I'm editing other people's code. I've always known that I ought to be commenting my changes
and I do it a lot more now that it's so easy.

How to use Intellisense


You can hack the FoxCode table directly but it's easier to start by using the IntelliSense
Manager. This is available on the Tools menu or by typing DO FoxCode in the Command
Window.

Select the Custom tab and type a new abbreviation - in this example I've used CB for 'Changed
By'.
Click the Script button and what looks like a procedure-editing window will open.
Write this code in the window:

LPARAMETER oFoxCode
LOCAL lcDate
&& System date as a string.
LOCAL lcComment
&& The text to be inserted.
lcDate = DTOC(DATE())
IF oFoxCode.Location = 1
*-- We're editing a program so make the substitution.
*-- The tilde marks where the insertion point will be.
*-- Note that there's a space after the tilde.
*-- The expression inside the <<double chevrons>>
*-- will be evaluated.
oFoxcode.valuetype = 'V'
TEXT TO lcComment TEXTMERGE NOSHOW

*-- ~
*-- Geoff Franklin - <<lcDate>>
ENDTEXT
ELSE
*-- We're not editing so return the keystrokes unchanged
lcComment = oFoxCode.Abbrev
ENDIF
RETURN lcComment

Save your changes by closing the edit window and the IntelliSense Manager.
Open a program edit window and test the new entry by typing CB. You should see the 'CB'
disappear and be replaced by the comments.
If it does not work, open the IntelliSense Manager and make sure that Enable IntelliSense is
ticked on the General tab.
Debugging a script is difficult. You can insert Set Step On into the code to open the debug
window and suspend execution but you cannot Resume again. The best way of debugging is to
go back to the old technique of adding DebugOut statements at crucial points.

Note that this piece of code used FoxPro's text merge commands.

Other uses
I've also modified the IntelliSense table entries to help me write HTML. I'm writing this page
now in VFP 7 and I've just inserted a pair of paragraph tags:
<p>
|
</p>

by typing the two-character code PP. This inserts the tags then moves up a line and two spaces
across so that my text will be nicely formatted.

FoxPro TextMerge

You can use the Copy To command to create a simple text file from a table with various forms of
delimiter between fields. The TextMerge commands let you create a more complex text file. The
contents can be a mixture of plain text, fields and variables, and FoxPro functions.
The commands are:

Set Textmerge On

Tell FoxPro to evaluate all the text it sees between the double chevron delimiters << and >>. If
necessary, these delimiters can be changed with the Set Delimiters To command.
Set Textmerge To <filename> Noshow

Direct the output to a file. The file will be created if it does not already exist. If the file does exist
and Safety is On then you will be asked whether you want to overwrite it. The Noshow clause
suppresses output to the screen and is useful if this command is being used in an application.
\xyz

Send the characters 'xyz' to the file. The characters are preceded by a carriage return/linefeed
combination. There is no need for quotes around the characters. If you put quotes around the
characters then the quotes will be output as well.
\\xyz

Send the characters 'xyz' to the file on the current line.


Set TextMerge To

Close the output file.


Set Textmerge Off

Stop evaluating expressions within << and >>.


<<foxpro expression>>

Evaluate the FoxPro expression. The expression can be the name of a field or memory variable
or a FoxPro function. The example below shows how you can mix <<foxpro expression>> with
plain text on the same line.

Text Merge Example


This example produces an HTML page holding a simple list of customers:
Use Customer
*-- Start the merge process
*-- Use the noshow option so that no output
*-- shows on screen
Set Textmerge On

Set Textmerge To customer.htm noshow


*-- Just a minimal HTML header for the document
\<html>
\<head>
\<title>HTML from FoxPro</title>
\</head>
*-- Now for the body
\<body>
*-- Start with a level 1 heading and a line
\<h1>Customer List</h1>
\<hr />
*-- Output one line for each record in the table
Scan
\Company name is <<Upper(Company)>>
\<br />
Endscan
*-- Closing tags for the html page
\</body>
\</html>
*-- Close the text file and stop merging
Set Textmerge To
Set Textmerge Off
Use In Customer

This short program will produce a text file named 'customer.htm' which looks like this in a
browser:

This is a very simple page but even so the mixture of TextMerge and HTML can be confusing to
write. Both use the < and > symbols and it's easy to get confused. TextMerge is however a very
powerful and flexible technique which lets you build a page which will display a mixture of text
and data.
Visual FoxPro offers other ways of generating HTML. These are described on the HTML from
FoxPro page.

Gotcha
There are two things to watch out for when using text merge and a third when using it to produce
HTML:

Everything on the line after a \ or \\, including any trailing spaces, will be output.
The carriage return/linefeed comes before the characters are output.
Remember that a \\ produces a new line of output in the text of the HTML file. It will not
produce a new line on the web page. You never really need to use a \\ when generating HTML
because browsers ignore new lines in the HTML source.

Scope
The SCAN command can take a scope clause if you need to produce a file based on a particular
set of records. More details on the scope of Visual FoxPro commands here.

Records affected by a FoxPro command


Looking at the FoxPro commands which deal with records in a table they fall into two broad
categories:

Destructive commands like Delete and Replace which default to the current record only.
Benign commands like Locate and Sum which default to the entire table.

This makes sense. If you make a mistake with a command like Delete then it's reassuring to
know that the damage has been limited to the current record and it won't be too much work to put
it right.
Most of these commands can take additional clauses to give you fine control over the records
that are going to be processed. There are 6 keywords:

All
For <logical expression>
Next <numeric expression>
Record <numeric expression>
Rest
While <logical expression>

These are described below but note that all of them will respect any filter so "all" in the next
section means "all the records available to the current filter."

All
As has been mentioned above, this is the default scope for many of the non-destructive
commands. It can however be applied to any of the others so for example:
Delete All

will delete all the records in the table.

For <logical expression>


The For clause will apply the command to every record which meets the logical criterion. For
example:
Delete All For City = "Bath"

will delete all records which have "Bath" in the City field.
The criterion for equality is controlled by the state of the Set Exact flag.

Next <numeric expression>


You should only use this clause if you are certain that the records are in a particular order and if
you are certain that you know where the record pointer is located. It restricts the command to the
next n records so a command such as:
List Next 50 to printer

will send the contents of the next 50 records to the printer, "next 50" meaning the next 50 records
according to the current index order. If no index order is in effect then the command will apply
to the next 50 record numbers.
The Next clause can be very useful for this sort of interactive usage but if you see it being used
in an application then you're usually looking at an old design with no relational features. It used
to be used where you would always have a block of ten records for each order because these held
details of the ten items that were permitted for each order. A better design would of course have
the item details in a separate table so that there could be any number of lines per order.

Record <numeric expression>


This clause also goes right back to the first days of FoxBase and forces the command to operate
on a given record number. These were the days of flat files and it seemed sensible to be able to
refer to a record by its position in the table rather than by any unique property such as the
Primary Key.
The syntax of this clause is:
Replace Record 3 cust_id With "DUMMY"

This syntax is supported by Visual FoxPro 9 but is not to be recommended. Nobody reading this
line will have any idea why record 3 is important.

Rest
Rest is another clause which relies on the position of the record pointer and on the order of the
records but this one can be very useful when you are tuning an algorithm for speed. If you can
arrange the records so that they are in a certain order then you might be able to design the
algorithm so that you can just process all the records from a certain point in the table:
Copy Rest to Customer.xls Type Xls

will copy all the records from the current position - including the current record - to an Excel
spreadsheet. This can be much faster than working through the entire set of records, picking and
choosing as you go.

If you don't need the current record then use the Skip command to move to the next record
before processing the "rest".

While <logical expression>


This does not have the same meaning as While in an SQL select statement. A command under
the control of While will execute against consecutive records as long as the criterion remains
true. This is not quite the same as a For clause which will operate on every record in the table
that matches the criterion. A While clause will stop as soon as it meets a record that fails to
satisfy the criterion. If the first record doesn't meet the criterion then no records at all will be
processed.
It's usual to use this clause in conjunction with a Seek command:
Set Order to Tag "City"
Seek ("Bath")
Replace County With "Avon" While City = "Bath"

This code will put the table into City order and then move the record pointer to the first record
for "Bath". Because the table is in City order we know that all the records for "Bath" will be in a
block following the current record and the While clause makes sure that we will process that
block of records and no more. If we had used a For here then the application would have
continued retrieving and examining the rest of the records in the table.
Careful use of While can reduce the running time of an algorithm from order n 2 to order n. If
you are processing all the deliveries for all the customers then a simple design would be to scan
the entire deliveries table once for each of the customers. By using While you can process the
deliveries for the first customer and then carry on from that point to process the deliveries for all
the following customers one at a time. This just takes one scan through the customer table and
one through the deliveries table.
As with the for clause, the definition of equality is controlled by the state of the Set Exact flag.

Exact matches

The way that the For and While clauses match records for equality
is controlled by the state of the Set Exact flag. This has a global value across the current data
session and can take either of the two string values "ON" and "OFF"
If Exact is "OFF" then two strings will be considered equal if the first letters of the longer string
match all the letters of the shorter string. The command:
Locate For Town = "Bath"

will find "Bath", "Bathavon", "Batheaston", etc. If Exact is "ON" then it will only find the exact
match of "Bath".
The default behaviour can be set by selecting Options from the Tools menu and picking the Data
tag.
Use the following commands to alter the state of Set Exact whilst a program is running:
Set Exact "On"
Set Exact "Off"

It is always a wise precaution to have one of these commands at the head of your program. This
ensures that, regardless of any local settings, you can be certain that your application will be
operating with exact or partial matches as appropriate. You will also need to repeat these

commands whenever you start a form with a private data session. The value of Set Exact is
restricted to the current data session.
Note that Set Exact only applies to string comparison using a single = operator. If the
comparison uses the double == operator then the two strings will only be considered equal if
they are the same length and any trailing spaces will be included in the comparison.

Set ANSI
Set Exact applies to the native FoxPro commands and not to records being selected by SQL
commands. The screenshot above shows that Set ANSI has also been set to "ON". This has a
similar effect on comparisons in SQL.

Copying data to CSV and other text files


from FoxPro
Migrating data between different applications can be a time-consuming job. XML promises to
make the work easier but there are still a lot of older applications which can't work with XML.
Sometimes the only way of exchanging data is to reduce it to a plain text format. Various
versions of FoxPro's Copy To command let you generate many different types of text file.
Each version of the Copy To command takes data from the current work area and exports it to a
new file. You can use the Fields clause to specify which fields you want and any of the scope
clauses to select the records. If you need a complex selection of the records or more sophisticated
processing, then use a query to select and process the data into a cursor and then export the data
from the cursor.
The Copy To command will export the contents of the current work area regardless of whether
this is a table, a cursor or a view. The limitation is that the command is restricted to the current
work area so you may have to change work areas before the export and change back afterwards.

Plain CSV file


It's very easy to generate a straightforward comma-separated (csv) file:
Copy To Town.csv Type CSV

This snippet of code will export all the fields of the current table into a text file with commas
between each field and with each record on a new line.

What does "delimited" mean?


This is an important question and one which can lead to misunderstandings between
programmers who come from different backgrounds. Be very careful when you hear this sort of
terminology. You will sometimes hear a CSV file being described as a "comma delimited file".
This phrase can be used to mean two different things so make sure that you know what is wanted
and ask for a sample of the data before you start work.
Some people would say that these few lines:
1,"Alvechurch"
2,"Bromsgrove"
3,"Catshill"
4,"Dudley"

are typical of the syntax of a comma delimited file. There are two fields in the table and each
record has its two values on a separate line.
There is a comma between each data value but you've probably taken the double quotes around
the names for granted because that's something of a standard in the PC world. The danger is that
we often have to use a csv file when we're sharing data with other computer systems and people
working on other operating systems might have a different understanding of the term "comma
delimited". They might say that that the output here was separated by commas but that each
string value was delimited by double quotes. You're unlikely to have any confusion when you're
talking about commas and quotes but if someone asks you to create a file delimited with
underscores or pipes then you really do need to see a sample so that you're sure that you
understand what is needed.
Note that it's only the string values which have delimiters. Numeric and date values stand alone.
Don't put braces around date values because that's FoxPro syntax. Access for example expects a
# character either side of a date.

Other delimiters
The extended syntax of the Copy To command starts by following one of these conventions for
the meaning of "delimiter" but then contradicts itself. For example, if we specify a dollar sign as
the delimiter:
Copy To Town.txt Type Delimited with $

then this command will produce a text file having the following structure:
1,$Alvechurch$
2,$Bromsgrove$

3,$Catshill$
4,$Dudley$

It's obvious that Fox is taking "delimited" to mean the characters marking the strings here. Three
further forms of the command take the opposite meaning and take "delimiter" to mean the
separator between fields:
Copy To Town.txt Type Delimited with Tab
Copy To Town.txt Type Delimited with Blank
Copy To Town.txt Type Delimited with Character _

These three commands will produce text fields with tabs, spaces and underscores between the
fields respectively. All of them retain double quotes as delimiters around the strings:
1
2
3
4

"Alvechurch"
"Bromsgrove"
"Catshill"
"Dudley"

1 "Alvechurch"
2 "Bromsgrove"
3 "Catshill"
4 "Dudley"

1_"Alvechurch"
2_"Bromsgrove"
3_"Catshill"
4_"Dudley"

Finally, we can mix the two terminologies and specify two different "delimiters", one between
the fields and another around the strings:
Copy To Town.txt Type Delimited With $ With Character _

This will give us underscores between the fields and dollar symbols around each string:
1_$Alvechurch$
2_$Bromsgrove$
3_$Catshill$
4_$Dudley$

It might look a little confusing but with a bit of experimentation you should find that you can
match most formats used to export data as plain text.

Fixed width data


The SDF format does not use delimiters or separators. Instead it generates files where each field
is output with trailing spaces at its full width:
Copy To Town.txt Type SDF

If the Town ID fields are four characters long and the Town Names are 15 characters long then
this example will generate:

1...Alvechurch.....
2...Bromsgrove.....
3...Catshill.......
4...Dudley.........

In this example the spaces have been shown as '.' for clarity and the paragraph markers have been
displayed.

Using matched pairs of delimiters


These different forms of the Copy To command let us generate a wide range of text formats but
they won't let us generate a text file which has paired separators such as [ and ] or HTML tags
like <b> and </b>. If you need to generate a more complicated format such as this example:
1,[Alvechurch]
2,[Bromsgrove]
3,[Catshill]
4,[Dudley]

then you will find Foxpro's TextMerge command useful.

Memo fields in a csv file


None of the forms of the Copy To command will copy memo fields to a csv file. The problem is
that the memo field is very likely to contain multiple lines of text and there's no recognised way
of storing line feeds and carriage returns in a memo field. One approach might be to store the
memo field as HTML. This will fit into the CSV format as plain text and it's easy to convert the
carriage returns and line feeds of the memo field into HTML:
Replace All memoField With Strtran(memoField, CHR(13) + CHR(10), "<br />")

This gives us a memo field of plain text but still leaves us with the problem that the the Copy To
command will not process a memo field. The solution again is to use the TextMerge function
inside a scan loop.
If you do have to create a csv file which includes memo fields then you must talk to the person
who'll be receiving and processing the file. They too are going to have to do some preprocessing
before they can import your data into their application and they might have restrictions which
make the whole process impossible. For example, the FoxPro memo field might be holding more
text than their import routine can accept.