Installing/Configuring Visual FoxPro 6.0
by Dennis Allen
Upgrading FoxPro 2.6a code to Visual FoxPro 6.0 is not that difficult. For the most part, FoxPro for Windows code is compatible with Visual FoxPro code. This tip sheet was created to cover the some of the basics.
FYI: If this sheet doesn't answer your question, check other web sites, such as Universal Thread
or Visual
FoxPro Wikis (for VFP Bugs, click here). You could
also post your problem
to the Microsoft
FoxPro forum or the google newsgroup microsoft.public.fox.programmer.exchange.
All information contained on this sheet is provided as is. There are no warranties, expressed or implied. The author and contributors may not be held liable for any damages, including any lost profits or other incidental or consequential damages arising out of or inability to use this information. Use of this information constitutes acceptance of this disclaimer. You should always double check any information before acting upon it.
This sheet contains references and/or links to other sites or to third party suppliers of goods and/or services. Such references or links should not be considered as an endorsement by the sponsors of this web site.
FoxPro 2.6a for Windows programs will recompile to Visual FoxPro 6.0. You may, however, have to adjust your code to handle Visual FoxPro. The following describes some of these changes:
@ PROMPT
If you still use @ PROMPT, time to replace it. Never looked good in FoxPro for Windows. Not any better in Visual FoxPro. I find using @ GET push buttons does a nice job simulating the @ PROMPT. The idea is to use the same variable for every @ GET. To save time, I've distilled my code for an example:
PUBLIC mCHOICE, mGET, cCHOICE, cCHOICES
STORE 0 TO mCHOICE, mGET
STORE "" TO cCHOICE, cCHOICES
nCOL = ROUND(WCOLS()/2,0) - 19
DO GET WITH 5,nCOL, "[\<1] - Create/Maintain Mailing List"
DO GET WITH 7,nCOL, "[\<2] - Create/Maintain State IDs"
DO GET WITH 9,nCOL, "[\<Q] - Quit this Menu"
cCHOICES = cCHOICES + "12Q"
cCHOICE = fnCHOICE(cCHOICES, "Q")
FUNCTION fnCUROBJ
PARAMETERS mCHOICE
mCHOICE = _CUROBJ
RETURN .T.
PROCEDURE GET
PARAMETERS nROW, nCOL, cFUNC, bSKIP
nSIZE2 = LEN(STRTRAN(cFUNC,"\<")) + 2
@ nROW,nCOL GET mGET FUNCTION "* "+IIF(bSKIP,"\\","")+cFUNC
;
DEFAULT 1 SIZE 1,nSIZE2 VALID fnCUROBJ(@mCHOICE)
RETURN
FUNCTION fnCHOICE
PARAMETERS cCHOICES, cDEF
READ CYCLE OBJECT mCHOICE
mCHOICE = IIF(LASTKEY()=27,AT(cDEF,cCHOICES),mCHOICE)
RETURN IIF(mCHOICE > 0,SUBSTR(cCHOICES,mCHOICE,1),"")
CLOSE DATABASES ALL
I started playing with Visual FoxPro 5/6 database containers. Even when you CLOSE DATABASE, a container is not quite closed. Try moving your DBC files and you'll get a sharing violation error. That means the files are still in use.
I found that [CLOSE DATABASES ALL] completely closes a database container. Oh, the [ALL] option doesn't seem to effect FoxPro 2.6 code at all.
BROWSE
Visual FoxPro, when you activate/release windows within a browse, the browse command loses focus. A problem only if you use popups. Two solutions. 1) After every window release, DEACTIVATE browse window. 2) Replace any dialog message window with WAIT "message" WINDOW NOWAIT.
Compiling Code
A neat trick I learned about FoxPro. You can compile FXP files with one version of FoxPro and create an APP file in another version, all in the same directory. How? Let's take my dMAIL4 application as an example.
The startup procedure is MAL.PRG. I compiled all FXP files in FoxPro 2.6, which created the startup MAL.FXP. I also built a Visual FoxPro VMAL.APP file, with MAL.PRG as the main procedure. By using a "V" prefix, I avoided creating a MAL.APP file, which would have erased the FoxPro 2.6 MAL.FXP file. Creating an APP file also avoids replacing the FoxPro 2.6 FXP files with Visual FoxPro FXP files.
Note: When I created the project VMAL.PJX, I only had to add MAL.PRG. By using explicit procedure calls, all other procedures automatically get incorporated into the project file.
FYI: A FoxPro 2.6 FXP or APP file will run in FoxPro 2.6 for DOS, Windows, Macintosh, or Unix. All you need is the correct runtime.
COPY TO
Visual FoxPro will use existing DBF files in the FoxPro 2.x format. But as DBF files get recreated, via COPY TO or PACK, the new DBF files will be in the Visual FoxPro format. Which is fine, unless you want to share DBF files with a FoxPro 2.6 version of your applications.
To keep files in the FoxPro 2.x DBF format, use the COPY TO TYPE FOX2X option. The following is typical code I use to retain the format:
IF "VISUAL" $ UPPER(VERSION())
PRIVATE cFILE3, cTEMP
cFILE3 = SYS(3)
DO WHILE cFILE3 = SYS(3)
ENDDO
CREATE (cFILE3) FROM (cFILE1)
cTEMP = "TYPE FOX2X"
COPY TO (cFILE2) &cTEMP.
USE (cFILE2)
ERASE (cFILE3+".DBF")
ERASE (cFILE3+".FPT")
ELSE
CREATE (cFILE2) FROM (cFILE1)
ENDIF
FYI: I bury the "TYPE FOX2X" option in a macro. This way, I can still compile the code in FoxPro 2.6 without a compiler error.
COPY TO TYPE DELIMITED
When FoxPro 2.6 creates a comma delimited file, date fields are created in yyyymmdd format. In Visual FoxPro, however, date fields are in mm/dd/yyyy format. This format is only a problem in Word for windows mail merge. To handle the date format, read the following from http://www.gmayor.dsl.pipex.com/formatting_word_fields.htm:
Word97: Testing for events that occur before or after a certain date
When running a mail merge, you may want to test for events that happen before or after a certain date. Mailmerge does not convert dates to numbers, so if you cannot automatically derive a date number from the date in the data file, as you could in (say) Excel, a different plan is called for.
Let's say the date comes into Word in the format d/MM/yyyy or 1/10/2002 (1st October 2002) from a mergefield called Startdate. In this example, we are looking to identify records with Startdate entries before 1st October 2002.
{if{mergefield Startdate}<1/10/2002 "True" "False"}
The above would appear the logical check, but the check treats the date as a number and identifies that number as 1, which is the first part of the number before the slash '/'. All dates other than the first of the month will be greater than 1, so all will produce the result "False".
We therefore need to display the date in numbers that represent the date in a unique way by using the date mask yyyyMMdd which displays the date as a series of digits for year month and finally day, without any breaks. This is a number that the conditional field will view as a whole.
{if{ref Startdate \@ "yyyyMMdd"} < 20020110 "True" "False"}
Thus any date before 1/10/2002 would produce "true" and any other date would produce "false".
DEFINE POPUP
This Visual FoxPro "feature" drove be nuts for years. If you use the IN WINDOW clause, the popup size takes on the characteristics of that window. Fonts, however, still originate from the Window's control panel. As a result, the popup will scroll. Even when you do not use the TO clause.
A remedy is simple. The Visual FoxPro DEFINE POPUP now has a FONT clause. Simply set the popup to the same font as your IN WINDOW.
Note: DEFINE POPUP FONT clause does not exist in FoxPro 2.6.
File/Record Locking
As everyone knows, you should perform FLOCK() before an APPEND BLANK and RLOCK() before you update a record. And, of course, you should always UNLOCK when you are done. But suppose you request a record lock at the very same instant someone else does it? You could use a do loop to retry the request. If someone else also retries and has the same speed of machine as you have, however, the two of you could flood the network with lock requests. A simple solution is to randomize the requests, as in the following function:
*
FUNCTION fnRLOCK
*
* THIS FUNCTION WILL ATTEMPT TO LOCK THE CURRENT RECORD IN THE CURRENT
* FILE. THE USER IS PROMPTED IF THE RECORD CANNOT BE LOCKED.
*
* PUBLIC:
* bMULT - FLAG, MULTIPLE USERS
*
* VARIABLES:
* nINKEY - USER INPUT
*
PRIVATE nINKEY
IF RECCOUNT() = 0 .OR. RECNO() > RECCOUNT()
RETURN .F.
ENDIF
IF .NOT. bMULT .OR. RLOCK()
RETURN .T.
ENDIF
DO ALERT WITH ;
"Record "+LTRIM(STR(RECNO()))+" in File "+UPPER(DBF())+"
in use...", ;
"Waiting for access, Press [ESC] to abort"
CLEAR TYPEAHEAD
nINKEY=INKEY(RAND()/2,"H")
DO WHILE nINKEY <> 27 .AND. .NOT. RLOCK()
nINKEY=INKEY(RAND()/2,"H")
ENDDO
DO ALERT WITH .F.
RETURN nINKEY <> 27
Filer
I've been trying to modify the Visual FoxPro 6 filer to be more like the FoxPro 2.6 filer. With help from the CompuServe forum, here's what I have so far:
In FoxPro 2.6, when you edit a file you can do a [Ctrl]-[G] for the next occurrence of your search text. For the VFP filer, I modified the filer.scx form (you can find this form in the tools/filer folder). In the first search textbox, I added _CLIPTEXT = ALLTRIM(This.Value) to the LostFocus of the 1st search textbox. When I run the VFP filer, however, I have to first [Ctrl]-[F], then [Ctrl]-[V]. Question. Does anyone know a way to get ALLTRIM(This.Value) directly into the VFP find dialog box? If so, please email me with a solution.
Here's a tip: The FoxPro 2.6 filer automatically MODI COMM all found files. To do the same thing in the VFP filer, do a MODIFY FORM filer.scx METHOD FIND. Find the following lines in the find procedure:
THIS.lstFiles.AddItem(IIF(LEFT(m.cFileName,2)="\\","\"+m.cFileName,m.cFileName))
ENDFOR
Before the ENDFOR, add:
THIS.lstFiles.Selected(THIS.lstFiles.ListCount) = .T.
To the very end of the find procedure, add the line: THISFORM.EditFile
Final word. If you don't have filer in your sysmenu already, add the following to your config.fpw:
COMMAND = DO FORM (HOME() + 'Tools\Filer\Filer.scx') with 0
This command will automatically add filer to the bottom of your tools pad.
Fonts
Moving from DOS to Window applications means working with fonts. If you wish to keep your software DOS/Unix compatible, there are a couple of things you can do.
I strongly suggest not using a proportional font, such as Arial. At the beginning of your application, add the line _Screen.Font = "Courier New". If you're windows fonts directory contains the font foxfont.fon, you could also try _Screen.Font = "foxfont".
For most DOS people, fonts mean dealing with smaller screens. My applications use GETFONT() to find a better font. I can define FONTNAME, FONTSIZE, and FONTSTYLE in a configuration file. My application reads this configuration file and sets the fonts via a MODIFY WINDOW SCREEN.
When dealing with DEFINE WINDOW, I like to include HALFHEIGHT. Keeps the title bar to a reasonable size. I also like to add an extra 1 to the column value of the SIZE clause. With fonts you don't deal with a 24x80 screen, more like a 25.01 by 80.145 size screen.
Which brings me to LEN(). As I said, with fonts you don't deal with whole numbers. To get a true LEN() of a string, I created a fnLEN() function:
*
FUNCTION fnLEN
*
*
* THIS FUNCTION RETURNS THE TRUE LENGTH OF STRING.
*
* PARAMETERS:
* cTXT - TEXT STRING
*
* PUBLIC:
* cFONT - FONT REQUIRED
* cSTYLE - STYLE REQUIRED
* nFONT - FONT REQUIRED
*
* VARIABLES:
* nLEN - TEMPORARY VARIABLE
*
PARAMETERS cTXT
IF TYPE("cTXT") <> "C"
RETURN 0
ENDIF
IF _DOS .OR. _UNIX .OR. EMPTY(cTXT)
RETURN LEN(cTXT)
ENDIF
nLEN = TXTWIDTH(cTXT,cFONT,nFONT,cSTYLE)
nLEN = INT(nLEN) + IIF(MOD(nLEN,1)>0,1,0)
RETURN nLEN
GETFILE()
Dialog functions like GETFILE(), GETFONT(), and PUTFILE() want to hog the screen. Any DEFINE WINDOW dialog message window disappears. If you want to display dialog messages, use either @ WROWS()-1,0 SAY "message", or do a WAIT "message" WINDOW NOWAIT.
Also for some reason, these functions always return LASTKEY()=13 in Visual FoxPro. Even on escape. I have yet to figure out how to fix this problem.
FYI: In my FoxPro 2.6 applications, I use KEYBOARD "&cFILE" PLAIN so that GETFILE() has a default file. This technique doesn't work in Visual FoxPro.
GETFONT()
GETFONT()) wants to hog the screen. Any DEFINE WINDOW dialog message window disappears. If you want to display dialog messages, use either @ WROWS()-1,0 SAY "message", or do a WAIT "message" WINDOW NOWAIT.
Also for some reason, this function always return LASTKEY()=13. Even on escape. I have yet to figure out how to fix this problem.
PUTFONT()
PUTFONT() wants to hog the screen. Any DEFINE WINDOW dialog message window disappears. If you want to display dialog messages, use either @ WROWS()-1,0 SAY "message", or do a WAIT "message" WINDOW NOWAIT.
Also for some reason, this function always return LASTKEY()=13. Even on escape. I have yet to figure out how to fix this problem.
I don't remember why, but my code uses GETPRINT() with a "Save" button as opposed to PUTFILE(). Maybe an earlier version of Visual FoxPro had a broken PUTFILE() function. Seems to work, but check it out before using.
A lot of people have problems with report frx files. Mostly because FoxPro for Windows/Visual FoxPro frx files store their own printer information. After you complete a MODIFY REPORT, the current printer is stored in the frx file. When you print a report, the frx file will send output to the stored printer. If that printer doesn't exist, however, results might be unpredictable. Could cause a computer crash.
There is a way to handle this situation. To print a report, try the following code (you'll want to modify this code to suite your needs):
=SYS(1037)
IF LASTKEY() = 27
RETURN
ENDIF
PRIVATE bFOUND, cCSRFRT, cCSRFRX, cTMPFRT, cTMPFRX, nDBF
cCSRFRX = SYS(3)+".FRX"
DO WHILE cCSRFRX = SYS(3)+".FRX"
ENDDO
cCSRFRT = STRTRAN(cCSRFRX, ".FRX",".FRT")
cTMPFRX = SYS(3)+".FRX"
DO WHILE cTMPFRX = SYS(3)+".FRX"
ENDDO
cTMPFRT = STRTRAN(cTMPFRX, ".FRX", ".FRT")
nDBF = SELECT()
SELECT 0
USE (cRPTFRX) ALIAS RPT SHARED
COPY TO (cTMPFRX)
USE IN RPT
CREATE CURSOR TEMP (TEMP C(1))
CREATE REPORT (cCSRFRX) FROM TEMP
USE IN TEMP
SELECT 0
USE (cCSRFRX) ALIAS CSRFRX EXCLUSIVE
SELECT 0
USE (cTMPFRX) ALIAS TMPFRX EXCLUSIVE
LOCATE FOR PLATFORM = PADR("WINDOWS",LEN(PLATFORM))
IF FOUND()
REPLACE TAG WITH CSRFRX->TAG, TAG2 WITH CSRFRX->TAG2
ENDIF
USE IN TMPFRX
USE IN CSRFRX
ERASE (cCSRFRX)
ERASE (cCSRFRT)
SELECT (nDBF)
REPORT FORM (cTMPFRX) TO PRINT NOCONSOLE NOEJECT
ERASE (cTMPFRX)
ERASE (cTMPFRT)
This code prompts the user for a printer. The selected printer is then installed on a temporary copy of the frx file, which is used to print the report.
On my systems, I go one step further. After a MODIFY REPORT, I prompt the user whether to keep the printer definition. If the user doesn't want to save it, I remove the printer definition from the frx file. When I'm ready to print the report, I check the frx file for a printer definition. If there is no definition, I invoke the above code example.
REPORT FORM PREVIEW
In Visual FoxPro for Windows, versions 5.0, 5.0a, 6.0, issuing a REPORT FORM <formname> PREVIEW with SET STATUS BAR ON causes Visual FoxPro to leak one memory handle each time you close the Preview window.
The solution is to issue a SET STATUS BAR OFF before previewing the report. In my applications, you can use the DOS environment variable SET STATUS = OFF to turn off the clock and status bar (see configuration manual).
Note: The Visual Studio 6.0 Service Pack 3 readme file lists this bug as fixed. SP3 did not fix this bug. Not confirmed, but SP5 might have fixed it.
REPORT FORM PREVIEW #2
I still can't use to the odd zoom effect of the VFP report preview. If you don't like it either, add the following code before the REPORT FORM command:
MOUSE CLICK AT 6, 36 WINDOW wreport
MOUSE CLICK AT 6, 36 WINDOW wreport
A variation would be:
MOUSE CLICK AT 10, 55 WINDOW wreport
MOUSE CLICK AT 9, 51 WINDOW wreport
SAVE SCREEN
In Visual FoxPro 6, SAVE SCREEN won't work if the screen is already blank (CLEAR). If the screen is blank, SAVE SCREEN TO will not create a screen memory variable. I found, however, preceding SAVE SCREEN with the command @ 0,0 SAY "" avoids the problem.
SET CENTURY
I always SET CENTURY ON to get 4 digit year prompts. Visual FoxPro has Y2K century rollover, so I use the following code in my applications:
SET CENTURY ON
IF "VISUAL FOXPRO" $ UPPER(VERSION())
cD = "SET CENTURY TO 19 ROLLOVER 60"
&cD
IF TYPE("SET('STRICTDATE')") <> "U"
cD = "SET STRICTDATE TO 0"
&cD
ENDIF
ENDIF
FYI: I bury the century rollover in a macro. This way, I can still compile the code in FoxPro 2.6 without a compiler error.
SET CPDIALOG OFF
By default, Visual FoxPro prompts you with a code page dialog box whenever it opens a dbf file without code page. To turn it off, add SET CPDIALOG OFF to your config.fpw file.
SET("PRINT",3)
If you start using the Visual FoxPro SET PRINT TO NAME, you'll need to save off the printer name for later restoration. The VFP6 function SET("PRINT",3) will save the current printer name, in uppercase. Due to a case sensitive bug in SET PRINT TO NAME, however, using just SET("PRINT",3) will lose printer page orientation. There is a workaround, using the APRINTER() function. Here's what I use to save/restore printer settings:
*save code
cPRINT = SET("PRINT")
cPRINT1 = SET("PRINT",1)
cPRINT3 = fnPRINT3()
*restore code
SET PRINT TO
IF .NOT. EMPTY(cPRINT1)
SET PRINT TO (cPRINT1)
ENDIF
IF .NOT. EMPTY(cPRINT3)
SET PRINT TO NAME (cPRINT3)
ENDIF
SET PRINT &cPRINT
*
FUNCTION fnPRINT3
*
IF .NOT. "VISUAL" $ UPPER(VERSION()) .OR. ;
TYPE('SET("PRINT",3)') <> "C"
RETURN ""
ENDIF
PRIVATE FLD, cPRINT3, nFLD
= APRINTER(FLD)
cPRINT3 = SET("PRINT",3)
IF .NOT. EMPTY(cPRINT3)
FOR nFLD = 1 TO ALEN(FLD,1)
IF UPPER(cPRINT3) = UPPER(FLD(nFLD,1))
cPRINT3 = FLD(nFLD,1)
EXIT
ENDIF
ENDFOR
ENDIF
RETURN cPRINT3
SET PRINT
In Visual FoxPro, you can now SET PRINT TO NAME "HP LJIII", where "HP LJIII" is an actual printer found in your windows print folder. You can also SET PRINT TO NAME GETPRINTER(). Upon printing, GETPRINTER() will prompt you with the list of available printer in the windows printer folder.
Note: Use GETPRINTER() or APRINTER() to get the exact printer name. SET PRINT TO NAME is case sensitive (see SET("PRINT",3)).
Using an undocumented SET PRINT option, you can set the printer's font, pitch, and style. For example:
SET PRINT FONT "FoxFont", 7 STYLE "N"
FYI: GETFONT() produces [FoxFont,7,N]. To be suitable for SET PRINT FONT you would have to add quotes and replace the second comma with STYLE.
SET SCOREBOARD OFF
If you SET SCOREBOARD ON, an input error might prompt with (Press SPACEBAR to continue). On some systems, I can't see this response message. To avoid the problem, I've added a new feature to my applications. User can now define an environment variable STATUS=OFF, which does a SET SCOREBOARD OFF.
SET STATUS BAR ON
In Visual FoxPro for Windows, versions 5.0, 5.0a, 6.0, issuing a REPORT FORM <formname> PREVIEW with STATUS BAR ON causes Visual FoxPro to leak one memory handle each time you close the Preview window. See REPORT PREVIEW.
SET STRICTDATE
SET STRICTDATE TO 0 simplifies working with date/time functions.
SYS(3)
If you use SYS(3) on a fast machine, always use it with a DO loop. Avoids duplicate file names.
cFILE = SYS(3)
DO WHILE cFILE = SYS(3)
ENDDO
"VISUAL" $ UPPER(VERSION())
In Visual FoxPro, the public variable _WINDOWS will be true. But the only way to tell if Visual FoxPro is running, as opposed to FoxPro 2.x for Windows, is to use the test "VISUAL" $ UPPER(VERSION()) or "VISUAL FOXPRO" $ UPPER(VERSION()).
People always ask me where to purchase a copy of Visual FoxPro 6.0. You might try either ebay.com or amazon.com.
Keep checking the ebay stores. Copies float on and off that site all the time. Also try
EMS Professional Software.
After installing Visual FoxPro 6.0, it's a very good idea to install the latest service patch. Microsoft still offers Visual Studio SP6, here. This patch should take you to Visual FoxPro 06.00.9266.00.
I hope you have found this tip sheet useful. If you have a tip to add, drop me an email (
[Return to Top]
[Go to Home Page]
Copyright © 2013 Dennis Allen.
This web page was last updated 03/13/15