Archive | FoxPro

The most powerful desktop database development environment in the known galaxy. Sadly owned by a company not interested in promoting it.

Sad News: Drew and Brent Speedie

Ted, Tamar, Drew, Whil, Art, BrentVery sad news: Drew Speedie (third from left) and his son, Brent Speedie (right) passed away while on vacation in Yellowstone.

Drew was a very talented man. He worked as the technical editor of “Hacker’s Guide to Visual FoxPro 3” and he helped Tamar and I make the book far better. Drew went on to develop the MaxFrame Professional framework. I used MaxFrame on a number of applications quite successfully. Drew was a contributing editor at FoxPro Advisor magazine where he wrote a number of insightful articles. Drew spoke at many FoxPro conferences around the world, always entertaining, always informative. He often attended the conferences in the company of son Brent and wife Irene.

He will be missed. My condolences to his family.

Randy Brown retires

FoxProWiki notes FoxTeam. Editor comments: Randy Brown – retired September 2005.

Congratulations, Randy! For those new(er) to Foxpro, Randy led a successful and remarkable life as a consultant before joining Microsoft as a Fox/Mac expert and author (Pros Talk Fox 2.5: FoxPro OLE and DDE, FoxPro Machete with Lisa Slater (now Nicholls), Doc Livingston and Andy Griebel.)

Best of luck in your future ventures, Randy!

So that’s what dog food tastes like!

At Shedding Some Light, Rick Schummer blogsThen it hits me. They finally fixed this little useful tool after it was broken for a long time. Now I know how a couple of the ViewEditor alpha testers felt last week when I finally tracked down and fixed the sorting bug in the list of tables and views when picking columns to be copied to the clipboard. Finally!

Whither .NET – additional ramblings

Andy Kramek posts a follow-up to his well-received essay: “Well, my little article on “Whither .NET” certainly prompted a variety of responses! I suppose it was to be expected that most of my regular readers are fellow FoxPro travelers and are probably pre-disposed to agree with my point of view. However what I found revealing was the comments from some people who obviously read something into my article that simply was not there.”

Hacker’s Guide named Developer’s Choice

FOR IMMEDIATE RELEASE

CONTACT:Ted Roche (XXX) YYY-ZZZZ
tedroche@compuserve.com

LOCAL AUTHOR RECOGNIZED WITH TOP PRIZE

Developer’s Choice Award

The Hacker's Guide to Visual FoxPro selected as the winner of the VFP DevCon 2000 Developer's Choice award.

The Hacker’s Guide to Visual FoxPro selected as the winner of the VFP DevCon 2000 Developer’s Choice award.

New Orleans, LA — (May 26, 2000) — Ted Roche of Contoocook, NH was awarded the highest honor in his field, the Developer’s Choice Award, last week at the VFP DevCon 2000 Connections conference. Roche, together with his co-author, Tamar E. Granor of Elkins Park, PA, was honored for his most recent book, Hacker’s Guide to Visual FoxPro 6.0 (Hentzenwerke Publishing.) The Developer’s Choice awards are co-sponsored by the conference organizer, International TechCon, LLC, and Pinnacle Publishing’s FoxTalk newsletter. The winners were selected by Visual FoxPro developers via an electronic ballot on the International TechCon web site.

The book is an irreverent and exhaustive reference to the Visual FoxPro programming language. Visual FoxPro is Microsoft’s programming environment for developing data-oriented desktop applications and middle-tier components. This is the second book Roche and Granor have co-authored. In 1996, their collaboration, Hackers Guide to Visual FoxPro 3.0 was published by Addison-Wesley.

Roche is the director of development at Blackstone, Incorporated, a Microsoft Certified Solutions Provider located in Waltham, Massachusetts. Blackstone develops Internet, database and faxing solutions and products for medium and large-scale businesses.

For further information:

Visual FoxPro: http://msdn.microsoft.com/vfoxpro
Hentzenwerke Publishing: http://www.hentzenwerke.com or (XXX) YYY-ZZZZ
International TechCon, LLC: http://www.vfpdevcon.com or(XXX) YYY-ZZZZ
Pinnacle Publishing’s FoxTalk newsletter: http://www.pinpub.com or(XXX) YYY-ZZZZ
Blackstone, Incorporated: http://www.bstone.com or(XXX) YYY-ZZZZ

###

COM Interfaces

(Reprinted from FoxPro Advisor, February 1999)
■ Visual FoxPro 6.0
Q: Here’s some strange behavior I ran across.The code below is a simple example of what I’m seeing. Run it from the Command Window, and you’ll be fine. Stick it in a project, build it into a COM .DLL, and change the CreateObject() call to use the .DLL. Run the code. Error: “Property not found”. What’s going on?

foo = CreateObject("FirstClass")
? foo.First.Name
? foo.First.Test
? foo.Second.Name
? foo.Second.Test
DEFINE CLASS FirstClass AS Custom olepublic
   name="MainContainer"
   FUNCTION Init
      this.AddObject("First","SecondClass")
      this.AddObject("Second","SecondClass")
   ENDFUNC
ENDDEFINE
 
DEFINE CLASS SecondClass AS Custom
   name="Second"
   test="teststring"
ENDDEFINE

—Dan Freeman, Chicago, Illinois

A: The problem has to do with the time at which the First and Second objects are bound to the interface of the MainContainer object. In Visual FoxPro, these objects can be
added as part of the class definition of the MainContainer, or can be added at a later time. Within Visual FoxPro, either technique works fine. The only significant difference between the
two techniques is that the objects added can’t be manipulated until they’re added.

The COM interface is a different matter. When the objects are compiled into a COM .DLL, a type library is produced that defines the outer interface of the .DLL. This type library is used by other languages such as Visual Basic, and development environments like Visual InterDev to display the interface using IntelliSense. The problem with this early binding of the interface is that it means the interface can’t be changed at runtime. When you attempt to reference newly-added objects in your COM .DLL, you have changed the interface in a way the controlling program can’t detect—it only has the static type library to go by.

One workaround is to define the interfaces as part of the compilation process so the type library properly reflects the interfaces you’ll be addressing. Two options exist for this. If the contained controls will always be the same ones, add them to the definition of the container with code like this:

DEFINE CLASS FirstClass AS Custom olepublic
   ADD OBJECT First as SecondClass
   ADD OBJECT Second as SecondClass
   name="MainContainer"
ENDDEFINE

The other alternative is just to fake out the type library generation by adding new properties to the outer container, and use them to hold references to the newly-created objects:

DEFINE CLASS FirstClass AS Custom olepublic
   First = .NULL.
   Second = .NULL.
   name="MainContainer"
   FUNCTION Init
      THIS.First = CreateObject("SecondClass")
      THIS.Second = CreateObject("SecondClass")
   ENDFUNC
ENDDEFINE

This technique gives you added flexibility in that you can decide which type of object to add to the container at runtime. The cost associated with this technique is that you lose the native containership model. That means you can’t address THIS.Parent in the added object, or use the Controls collection of the container object to access the First and Second objects. I prefer the second solution. I pass THIS as a parameter in the
CreateObject() for the new object, then store the reference in the contained object to give it a callback reference to the “parent.”

As long as one of the contained objects has a reference to the “parent,” the container can’t be released. So, be sure to set the First and Second properties to .NULL. in the Destroy event of the container, thereby releasing these objects before the container is released.

—Ted

Empty Dates and Client-Server

(Reprinted from FoxPro Advisor, January 1999)
■ Visual FoxPro 6.0/5.0/3.0
Q: When a Visual FoxPro table has an empty date, the Upsizing Wizard puts January 1, 1900 in the SQL Server table. Can this be overridden?
—Benjamin A. Aminnia (via CompuServe’s VFox forum)

A: You can’t override how the Upsizing Wizard handles your tables, but consider replacing the empty values in the table with .NULL.; ODBC and most other data sources have no equivalent for the “empty” value that FoxPro stores. Most ODBC data sources have a default value of {^1900-01-01} (sometimes {^1899-12-31} or {^1899-12-30}, depending on the product and whether they counted leap years correctly).
So, to get blank dates represented properly in other data formats, you need to use the .NULL. value. You need to modify the code within your system to handle null values by using the ISNULL() and NVL() functions.
NVL() is a clever little function that makes handling nulls much easier. It’s like a built-in:

IIF(ISNULL(YourVariable) , NewValue, YourVariable)

—you can shorten that to

NVL(YourVariable, NewValue)

—Ted

Converting CardFiles to FoxPro tables

Import Non-.DBF Data

Explore one of the many uses of low-level file

functions: Convert Cardfile data to FoxPro tables.

By Ted Roche

[Originally published in FoxPro Advisor, January 1995]

What are LLFFs?

Low-level file functions (LLFFs) provide the ability to read and write files in foreign file formats within FoxPro. These files can be in any format—text files, binary data, such as bitmaps, or even .EXE files. (Caution: You’ll probably want to experiment on copies of important files, as there is no UnDo() function.) In this article, I discuss and demonstrate reading a Windows Cardfile into a FoxPro database. While LLFFs also provide limited ability to access other DOS devices (such as the serial port) directly, the focus of this article is on file manipulation.

Why use LLFFs?

Low-level file functions are useful in so many situations, your imagination may be all that limits them. LLFFs are used to read system files, such as CONFIG.SYS and AUTOEXEC.BAT, to ensure that required settings or commands are present. They are also used to read and correct corrupted FoxPro databases or indexes. As a security measure, they can be used to make your application’s .DBF files unreadable by others. Or, as in the example given here, they can be used to read in data files whose format is not supported by FoxPro’s IMPORT command.

How to use LLFFs

Using LLFFs in your program doesn’t require a different programming structure or approach than you have used for FoxPro’s native high-level functions. The main difference is that you need to be aware of any structure built into the files, whereas FoxPro knows how to work with .DBF, .CDX, and .FPT files. In fact, you could look at low-level file functions as providing access to files that consist of a sequence of one-byte records. Rather than USEing a database, you FOPEN() or FCREATE() a file. Instead of an alias or select area, you specify the file you’re using by referring to the file handle returned by the functions.

Rather than SCATTERing the contents of a .DBF’s fields, you FREAD() one or more bytes or FGETS() characters up to the next carriage return in the file. Conversely, you would FWRITE() one or more bytes or FPUTS() a character string, rather than REPLACEing or GATHERing memory variables to disk.

Because the file consists of unindexed one-byte records, there’s no equivalent to SEEK or LOCATE. Instead, you just FREAD() until you find the character you’re looking for. However, if you know the location in the file where you want to work, the FSEEK() function works similarly to the GO and SKIP

commands to reposition you within the file.

Finally, when you’re done with the file, you FCLOSE() it, just as you would USE a .DBF when done.

Error handling

LLFFs have their own error-handling capabilities that are separate from the usual ON ERROR trapping used by FoxPro. There are two levels of error handling. First, check for proper response when issuing a function. Then, investigate details of the error using the FERROR() function. For example, when FOPEN() is used, a non-negative number is returned if the file is opened successfully. If a negative number is returned, you know an error has occurred and you can proceed from there. Similarly, the reading, writing, and pointer repositioning functions return the number of bytes processed, so that an incomplete process can be detected and handled appropriately.

Putting LLFFs to work

The sample code in this article, demonstrates importing data from Windows’ Cardfile format. Cardfile is a Windows applet, a simple demonstration application that ships with Windows. It has basic indexing, search, and autodial capabilities and uses few resources, limiting itself to a 64K memory segment. For a simple database application or for machines severely limited in resources, Cardfile is a handy way of letting users view names, addresses, or other company information without incurring the heavy overhead of keeping a FoxPro session running.

The application, included on this issue’s COMPANION RESOURCE DISK and reproduced here, consists of three files. READCARD.PRG is the project’s main file and the driving program, ASC2Num.PRG is a UDF to convert binary-stored numbers to numerics, and LLError.PRG is a generic low-level error handler.

Bear in mind these are simplified routines designed to illustrate basic functionality, and additional safeguards may be needed for a commercial-grade application. The COMPANION RESOURCE DISK also contains a sample Cardfile containing the text of Lincoln’s Gettysburg address. (See the sidebar “Windows Cardfile Format” later in this article for a description of a Cardfile format.)

Main Program – READCARD.PRG

* READCARD.PRG - read in cardfile database
* Purpose: Read a Window CardFile,
*
Write a DBF
PRIVATE ALL LIKE L*
* Select Input CardFile and Output DBF *
****************************************
lcCardFile = GETFILE("CRD", ;
"Read which cardfile?","Read",0)
IF EMPTY(lcCardFile) OR NOT FILE(lcCardFile)
* Cancel or no file
RETURN
ENDIF
lcCardDBF = PUTFILE("Save As:", ;
STRTRAN(lcCardFile, "CRD", "DBF"), ;
"DBF")
IF EMPTY(lcCardDBF)
* an empty return -> cancel selected
RETURN
ENDIF
* Open the input Cardfile *
***************************
lnCardHandle = FOPEN(lcCardFile,0)
IF lnCardHandle = -1
DO llError
ENDIF
* Create the output table *
***************************
CREATE TABLE (lcCardDBF) (Topic C(50),Contents M)
* Read CardFile Header *
************************
IF FSEEK(lnCardHandle,0,0) # 0
DO llError
ENDIF
&& go to BOF
lcFileType = FREAD(lnCardHandle,3)
IF lcFileType # "MGC" AND lcFileType # "RRG"
WAIT WINDOW lcCardFile + ;
"is not a valid CardFile."
=FCLOSE(lnCardHandle)
RETURN
ENDIF
* Calculate the number of cards *
*********************************
* # cards, binary
lbCardCnt = FREAD(lnCardHandle,2)
DO llError
* # cards, decimal
lnCardCnt = ASC2Num(lbCardCnt)
* Loop through the cards *
**************************
FOR lnCardNum = 1 TO lnCardCnt
* read in cards
* Display a status window *
***************************
WAIT WINDOW NOWAIT "Reading card #" ;
+TRANSFORM(lnCardNum,"999")
* Position at the record *
**************************
lnPosition = 11 + 52 * (lnCardNum - 1)
IF lnPosition # FSEEK(lnCardHandle,lnPosition,0)
DO llError
ENDIF* The first five characters point to
* the location of the card's contents *
***************************************
* offset,binary
lbContPtr = FREAD(lnCardHandle,5)
DO llError
* offset, decimal
lnContPtr = Asc2Num(lbContPtr)
* Read the Topic *
******************
lcTopic = FREAD(lnCardHandle,47)
DO llError
ln0End = AT(CHR(00),lcTopic)
lcTopic = iif(ln0End=0, ;
lcTopic,left(lcTopic,ln0End-1))
* Reposition to the Contents & Read *
*************************************
IF lnContPtr+2 # ;
FSEEK(lnCardHandle,lnContPtr+2,0)
DO llError
ENDIF
lbContSize = FREAD(lnCardHandle,2)
DO llError
lnContSize = Asc2Num(lbContSize)
IF lnContSize # 0
lcContents = FREAD(lnCardHandle,lnContSize)
DO llError
ELSE
lcContents = ""
ENDIF
* Create the output record *
****************************
INSERT INTO (lcCardDBF) ;
(Topic
, ;
Contents) ;
VALUES
;
(lcTopic , ;
lcContents)
NEXT
=FCLOSE(lnCardHandle)
RETURN

ASCII-to-numeric conversion UDF

Asc2Num.PRG
* Asc2Num
* Convert multi-character hi-byte, lo-byte
* to decimal
PARAMETER tcString
PRIVATE lnNum
* Trim off ending CHR(00)'s
DO WHILE RIGHT(tcString,LEN(tcString)) = CHR(00)
tcString = LEFT(tcString,LEN(tcString)-1)
ENDDO
lnNum = 0
FOR i = LEN(tcString) TO 1 STEP -1
lnNum = lnNum + ;
ASC(SUBSTR(tcString,i,1))*256^(i-1)
NEXT
RETURN lnNum

Low-level file function error handler

* LLError.PRG
* Low Level Error Handler
PRIVATE ALL LIKE l*
IF FERROR() # 0
DO CASE && Determine which error
CASE FERROR() = 2
lcReason = 'File not found'
CASE FERROR() = 4
lcReason = ;
'Too many files open (out of handles)'
CASE FERROR() = 5
lcReason = 'Access denied'
CASE FERROR() = 6
lcReason = 'Invalid file handle given'
CASE FERROR() = 8
lcReason = 'Out of memory'
CASE FERROR() = 25
lcReason = 'Seek error'
CASE FERROR() = 29
lcReason = 'Disk full'
CASE FERROR() = 31
lcReason = 'General Failure'
OTHERWISE
lcReason = 'Unknown LL error '+ ;
LTRIM(STR(FERROR()))
ENDCASE
*** Display the error ***
WAIT WINDOW "Low level file error: "+ ;
lcReason NOWAIT
CLOSE ALL
CANCEL && you may want to return to master
ENDIF
RETURN

Windows Cardfile Format

The complete file format for Windows Cardfiles is in the Microsoft Knowledge Base as article #Q99340. The file formats for many types of data files are either documented by the manufacturer, or by third parties in books and magazines. Once the format is known, FoxPro’s low-level file functions let you go in and get the data.

Cardfile 3.0 Header

Bytes
Contents
0,1,2
Signature / version bytes, always "MGC" for 3.0 and for 3.1 files containing only text, "RRG" for 3.1 containing OLE
objects 
3,4
No. of cards, high byte, low byte format Cardfile 3.0 Index line
0,5
Reserved for future use, always CHR(00)'s
6-9
Pointer to card's body text
10
Always CHR(00), 'flag byte'
11-50
Index text (appearing atop card)
51
Always CHR(00)

 

Cardfile 3.0 Body

Bytes
Contents
0,1
length of body text (440 characters max)
2-xxx
body text

Ted Roche enhances Xbase systems and trains programmers in more efficient development techniques. He is a 1994 recipient of the Microsoft Support Most Valuable Professional Award. Ted has published several articles, contributed to two books on FoxPro, and was a technical editor for four FoxPro 2.5 books. He is co-editor of the Boston Computer Network News, and is a frequent speaker at user group and professional conferences. CompuServe 76400,2503.

Copyright 1995, 2017 by Ted Roche under a Creative Commons Attribution, Share-alike, Non-commercial license.

Powered by WordPress. Designed by Woo Themes

This work by Ted Roche is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States.