Installing/Configuring Visual FoxPro 6.0
by Dennis Allen

Table of Contents (3/17/2005)

Disclaimer

Programming Changes

Summary

Index

 

 

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.

Before I begin, I'd like to thank everyone on the CompuServe MS Developer forum, plus all the people on the Internet newsgroup microsoft.public.fox.programmer.exchange.

 

Disclaimer

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.

 

Programming Changes

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.

For most DOS people, fonts mean dealing with smaller screens. What I do is use GETFONT() to find a better font. I 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.

 

REPORT FORM

 

 

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

 

Visual FoxPro has Y2K century rollover. I use the following code in my applications:

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("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.

 

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()).

 

Summary

 

I hope you have found this tip sheet useful. If you have a tip to add, drop me an email (

 

For additional information, try the Internet newsgroup: microsoft.public.fox.programmer.exchange

You might want to check out the Microsoft FoxPro web site:

http://msdn.microsoft.com/vfoxpro.

If you still need more help, check out my web site http://www.dennisallen.com/ Favorite (hyper) Links section:

 

Index

Return to Home

Copyright © 2005 Dennis Allen.

This web page was last updated 11/29/11