RAS
Home
Welcome to RickSchummer.com
web site hosted by GoDaddy Software

(Version 4.5.19 - This site updated 02-Apr-2005)
 

What is new?

Favorites

Site Map

About RAS



United We Stand!

Blog

VFP Tools

VFP Books

VFP Announcements

Articles

Presentations

GLGDW 2001 Pictures

DevCon 2000 Pictures

Set Up Your Dot Com


Site Policies

Curriculum Vitae
Resume

Words of Wisdom

Track Space Station

Campgrounds

US States Visited

Browser Details

Photography Index

Biscuit Photos

Rocketry 2001 Photos


Older Information

News

RAS.Commentary

Great Truths

Websites of the Month

What was new (v3.x)

What was new (v2.x)

What was new (v1.x)


FoxPro’s Project File

By Richard A. Schummer

Originally Published in the November 1994 issue of FoxTalk 

Copyrighted 1994 - Richard A. Schummer

The FoxPro project is maintained in nothing more than a database table. Many FoxPro developers already know this, but what many might not know is some of the ways this file can be exploited. The project file can be used for more than tracking all files within an application and creating executables. This article will discuss how the FoxPro project file can be utilized to create everything from a basic checklist of files within the project to some pretty handy technical documentation for your application. Since I am lazy like most developers, I much prefer using tools to generate as much of my application’s documentation as possible. I will also discuss in some detail how a project file is structured.

Back to Basics

Since FoxPro 2.0 was released a few years ago, developers have been able to organize all files associated with an application using the Project Manager power tool. The Project Manager offers many features to a developer. First, quick access to objects (such as screens, reports, menus, programs) in the project. Second, an organized list of objects that comprise a project. Third, the ability to combine these objects into an executable file (.APP or .EXE). And lastly, the project tracks detailed information about each object in the application which is the focus of this article.

As I stated before, a project is stored in a database table. To make them standout from other databases, the project files use .PJX as the extension and the associated memo file has a .PJT extension. This extension allows developers to distinguish a project file from other FoxPro generated tables for data, screens, menus, reports forms, and labels.

Why Ask Why?

My first stop in my quest for understanding the project file was to just BROWSE the database. This can be easily done by opening up a project as a database, not as a project. To do accomplish this, USE the database (always include the extension):

USE <project> EXCLUSIVE NOUPDATE

BROWSE LAST

The NOUPDATE option on the USE statement serves as a protection from corrupting the project file as you look at the information. This could prove important if you hit a key by accident while on a field. Any errant changes could cause problems with the screen builder, menu builder, or transporter. I can not stress the importance of this added option any more than to always use it.

Viewing the contents of the project file only made me want to know more about all the different fields and their contents. The Microsoft Fox development team and technical writers have been very kind in providing all FoxPro developers with detailed documentation on the file layout for the project file, screen files, report forms, menu files, database tables and indicies. This documentation can be found in the FoxPro Developer Guide Appendix A. The project file layout is as follows:

NAME        Memo          10

TYPE        Character      1

TIMESTAMP   Numeric       10

OUTFILE     Memo          10

HOMEDIR     Memo          10

SETID       Numeric        4

EXCLUDE     Logical        1

MAINPROG    Logical        1

ARRANGED    Memo          10

SAVECODE    Logical        1

DEFNAME     Logical        1

OPENFILES   Logical        1

CLOSEFILES  Logical        1

DEFWINDS    Logical        1

RELWINDS    Logical        1

READCYCLE   Logical        1

MULTREADS   Logical        1

NOLOCK      Logical        1

MODAL       Logical        1

ASSOCWINDS  Memo          10

DEBUG       Logical        1

ENCRYPT     Logical        1

NOLOGO      Logical        1

SCRNORDER   Numeric        3

CMNTSTYLE   Numeric        1

OBJREV      Numeric        5

COMMANDS    Memo          10

DEVINFO     Memo          10

SYMBOLS     Memo          10

OBJECT      Memo          10

CKVAL       Numeric        6

The Project Header Information

All the project specific information is maintained on the project header record (Where Type = “H”). This includes all the options that you can set from the Project Options... menu within FoxPro. The authors name and address is stored in the DEVINFO field, the save code option is stored in the SAVECODE field, and the generated code location is stored in the OUTFILE field. The OUTFILE will either have the directory name where all generated code is stored, or indicate if it is stored with the <Source> files, or in the <Project> directory. The HOMEDIR field usually contains the absolute directory where the project file is stored. If the project was developed using FoxPro/MAC and the project file is not a DOS path name, the path will be stored in the ASSOCWINDS memo field. The debugging, encrypt code, and display logo options are stored in DEBUG, ENCRYPT, and NOLOGO respectively. The comment style appropriately maintained in the CMNTSTYLE field.

I have created a function that returns the project header information in a descriptive English format in a function called MemoCreateFN. This function is discussed as part of the screen information. For now you can examine the project detail using the following SQL-Select:

SELECT * ;

  FROM <project file> ;

  WHERE Type = "H" ;

  INTO CURSOR ProjInfo

Where <project file> is the project file database with the .PJX extension. Please note that you must include the extension since FoxPro will default to the .DBF extension. This information can then be browsed, sent to a report, or displayed on a screen.

What is in a name?

The NAME field contains the name of the object. The object name is stored in a format which includes the normalized path. It basically stores the relative path to the home directory of the project file along with the file name. For instance, if you have a screen saved as ABOUT.SCX in SCREENS directory under a project, the NAME field will contain SCREENS\ABOUT.SCX.

The last character in the NAME field is the NULL character (ASCII 0). You will find the NULL character in many of the memo fields throughout the project file. It is used by FoxPro to indicate the end of the data within the memo field.

To get just the name of the file I developed a simple user defined function (UDF) that will return just the name of the file without the null character. I strip off the null character because when the field is displayed in the FoxPro/WIN report form print preview mode, it shows up as an empty square. If you are a FoxPro/DOS developer, please note that the null character is not displayed in FoxPro/DOS print preview. Here is the UDF:

*************************************************

*

*             S H O R T N M E . P R G

*

*  AUTHOR: Richard A. Schummer     September 1994

*          CompuServe Id # 70254,1643

*

*  PROGRAM DESCRIPTION: 

*     This procedure strips off the relative 

*     directory of the file name.  

*  CALLING SYNTAX: 

*     <variable> = ShortNme(<path/filename>)

*

*     Sample:

*     cFileName = ShortNme(Name)

*

*************************************************

 

PARAMETER cFileName

 

PRIVATE cRetString             &&  Value returned

 

cRetString = UPPER(SUBSTR(cFileName, ;

                          RAT("\",cFileName)+1))

 

* Eliminate all Null characters from field passed

* to procedure.  This removes the "box" character

* displayed in field during the Windows print

* preview.

 

RETURN  STRTRAN(cRetString, CHR(0), "")

 

*: EOF :*

 

 

I frequently wanted a list of the file names within a project. I also like to group all the files of an object type together. This can easily be done with the following SQL-Select:

 

SELECT *, ShortNme(Name) AS cShortName ;

  FROM <project file> ;

  ORDER BY    Type, cShortName ;

  INTO CURSOR query

If you want a specific object type, add a Where clause to the above SQL-Select using the TYPE field as the filtering condition. You can either browse this list of files or create a quick report that lists the query results to the printer or preview it to the screen. This quick routine provides a check list of the different objects within the project.

The Time Stamp Decoded

The TIMESTAMP field is not a date type field, it is numeric. I am guessing, but I think the FoxPro development team used this method of time stamping to save space on the record, make it easier to compare time stamps when verifing which objects need recompiling during an application build, and for transporting objects in cross-platform applications. If the TIMESTAMP field is zero, the file has not been “built” into the project yet. 

This field is a 32-bit (numeric compressed) system based on the year 1980 that allows both the date and time to reside all in one field. It took me some time to track down the algorithm. Fortunately Randy Brown explained the TIMESTAMP field in his Advanced Screen Builder Techniques session material from Microsoft’s FoxPro DevCon 1993. I reversed engineered this routine to determine what the TIMESTAMP represents (I later found out that several others posted notes on CompuServe). During development of the algorithm I found my routine was always adding 30 seconds to the time if the actual time the file was saved was between 30 seconds and 59 seconds within a minute. I had to call Microsoft Tech Support to find out that there was a “bug” in the logic for decoding the TIMESTAMP field. Microsoft built in a truncation of the right most bit, therefore the last bit is multiplied by two, instead of just adding the last bit in.

The following routine allows the calling program to request the return string to be only the date, only the time, or the date followed by the time. Here is the program:

*************************************************

*

*             T S T M P 2 D T . P R 

*

*  AUTHOR: Richard A. Schummer    September 1994

*

*  PROGRAM DESCRIPTION: 

*     This procedure handles the conversion of

*     the FoxPro TIMESTAMP field to a readable

*     (and understandable) date and time.  The

*     program will return the date/time in three

*     formats based on the cStyle parameter.

*

*  CALLING SYNTAX: 

*     <variable>=TStmp2Dt(<nTimeStamp>,<cStyle>)

*

*     Sample:

*     m.cDateTime=TStmp2Dt(TimeStamp,"DATETIME")

*

*************************************************

 

PARAMETER nTimeStamp, cStyle

 

PRIVATE cRetVal   &&  Requested data returned 

                  &&  from procedure

 

* Timestamp must be numeric

IF TYPE('nTimeStamp') != "N"

  WAIT WINDOW "Time stamp passed is not numeric"

  RETURN ""

ENDIF 

 

* Timestamp is zero until built in project

IF nTimeStamp = 0

  RETURN "Not built into App"

ENDIF

 

* Default return style to both date and time

IF TYPE('cStyle') != "C"

  cStyle = "DATETIME"

ENDIF

 

IF !INLIST(UPPER(cStyle), "DATE", "TIME", ;

                          "DATETIME")

  WAIT WINDOW "Style parameter must be " + ;

              "DATE, TIME, or DATETIME"

ENDIF

 

 

* Multiply by two to correct truncation problem 

* built in to the creation algorithm

* (Source: Microsoft Tech Support)

 

nYear   = ((nTimeStamp/(2**25) + 1980))

nMonth  = ((nYear-INT(nYear)    )*(2**25))/ ;

                                  (2**21)

nDay    = ((nMonth-INT(nMonth)  )*(2**21))/ ;

                                  (2**16)

 

nHour   = ((nDay-INT(nDay)      )*(2**16))/ ;

                                  (2**11)

nMinute = ((nHour-INT(nHour)    )*(2**11))/ ;

                                  (2**05)

nSecond = ((nMinute-INT(nMinute))*(2**05))*2

 

 

cRetVal = ""

 

IF "DATE" $ UPPER(cStyle) 

  cRetVal = cRetVal + ;

            RIGHT("0"+ALLTRIM(STR(INT(nMonth))),2) ;

            + "/" + ;

            RIGHT("0"+ALLTRIM(STR(INT(nDay))),2) ;

            + "/" + ;

            RIGHT("0"+ALLTRIM(STR(INT(nYear))),2)

ENDIF

 

IF "TIME" $ UPPER(cStyle)

  cRetVal = cRetVal + ;

            IIF("DATE" $ UPPER(cStyle), " ", "")

  cRetVal = cRetVal + ;

            RIGHT("0"+ALLTRIM(STR(INT(nHour))),2) ;

            + ":" + ;

            RIGHT("0"+ALLTRIM(STR(INT(nMinute))),2);

            + ":" + ;

            RIGHT("0"+ALLTRIM(STR(INT(nSecond))),2)

ENDIF

 

RETURN cRetVal

Adding onto the previous SQL-Select, we can now get the date and time stamp added on to the project listing.

SELECT *, ShortNme(Name) AS cShortName, ;

       TStmp2Dt(TimeStamp,"DATETIME") AS cDate, ;

  FROM <project file> ;

  ORDER BY    Type, cShortName ;

  INTO CURSOR query

Screen Components

The project file stores all of the screen set generated code options that you initialize on the Edit Screen Set screen in the project file. If you have ever generated screen code independent of the project manager you will notice that the settings are never saved from one generation to another. They always default to the FoxPro generic settings (open and close files, define and release windows, border for GETs, and READ Cycle). This is because the settings are stored in the project file on the type “S” records within the project file. The options to open and close files are stored in the OPENFILES and CLOSEFILES fields respectively. Defining windows is stored in the DEFWINDS field and releasing windows is maintained in the RELWINDS field. If the screen set is modal the MODAL field is set to true (.T.).

The following procedure returns a string with the detail of screen settings spelled out. This routine also includes the logic for the project header details. By calling this function all the project header information and screen details will be viewable in English for a report on the project:

FUNCTION MemoCreateFN

 

PRIVATE cRet   &&  Value returned by

               &&  the function

 

DO CASE

CASE  Type = "H"

 cRet = IIF(Debug, "Debug code created, ", ;

                   "No debug code, ")+ ;

        IIF(Encrypt, "App is encrypted, ", ;

                     "App is not encrypted, ")+ ;

        IIF(NoLogo, "No FoxPro logo at start up, ", ;

            "Shows FoxPro logo at start up, ")+ ;

        "Comment style is "+ ;

        IIF(CmntStyle=0, "box, ","asterisk, ")+ ;

        IIF(SaveCode, "Generated code is saved in " + ;

            ALLTRIM(STRTRAN(OutFile, CHR(0), "")) + ;

            " directory,","Generated code is not saved,")+ ;

        IIF(EMPTY(DevInfo),"", ;

            CHR(13)+ALLTRIM(STRTRAN(DevInfo, CHR(0),;

            IIF(_DOS OR _UNIX,CHR(13),CHR(32)))))

 

CASE  Type = "S"

 cRet = IIF(OpenFiles, "Files opened, ",;

                       "Files not opened, ")+ ;

        IIF(CloseFiles, "Files closed, ", ;

                        "Files not closed, ")+ ;

        IIF(DefWinds, "Windows defined, ", ;

                      "Windows not defined , ")+ ;

        IIF(RelWinds, "Windows released , ", ;

                      "Windows not released, ")+ ;

        IIF(ReadCycle,  "READ CYCLE, ", ;

                        "Not READ CYCLE, ")+ ;

        IIF(Modal, "Modal, ", ;

                   "Not modal, ")+ ;

        IIF(MultReads, "Multiple READs, ", ;

                       "Not multiple READs, ")+ ;

        IIF(NoLock, "READ NOLOCK, ", ;

                    "Not READ NOLOCK, ")+ ;

        IIF(SaveCode, "Windows objects only, ", ;

                      "Cross platform objects, ")+ ;

        IIF(DefName, "Defaulted ", ;

                     "Not defaulted ")+ ;

        IIF(EMPTY(AssocWinds),"", ;

                     CHR(13)+"Associated Windows: "+ ;

                     ALLTRIM(AssocWinds))

OTHERWISE

 cRet = " "

ENDCASE

 

RETURN cRet

The next set of code delivers all the information about the object name, the date and time of the object file, and details about the project header and screens. The first section of code does a quick query of the project file and determines the date and time of the files. The section following this is creating a temporary cursor with two additional fields, one for the object name, the other for notes on the project and screens. The memo field is especially important since calling the MemoCreateFN on a project would return a character type field (usually one byte long) which leads to possible truncation of project header and screen details. The last section determines the details and builds the cursor which is finally queried to sort the information by object type and name.

SELECT *, ;

FROM projlist.pjx ;

  INTO CURSOR query

 

nRows = AFIELDS(ac_Stru)

 

* Contains table definition information

DIMENSION ac_Stru(nRows+4,4)

 

* Add ShortName field to newly created cursor

ac_Stru(nRows+1,1) = "cShortName"

ac_Stru(nRows+1,2) = "C"

ac_Stru(nRows+1,3) = 12

ac_Stru(nRows+1,4) = 0

 

* Add date and time field to newly created cursor

ac_Stru(nRows+2,1) = "cDateTime"

ac_Stru(nRows+2,2) = "C"

ac_Stru(nRows+2,3) = 17

ac_Stru(nRows+2,4) = 0

 

* Add mNotes field to newly created cursor

ac_Stru(nRows+3,1) = "mNotes"

ac_Stru(nRows+3,2) = "M"

ac_Stru(nRows+3,3) = 10

ac_Stru(nRows+3,4) = 0

 

* Add mDirName field to newly created cursor

ac_Stru(nRows+4,1) = "mDirName"

ac_Stru(nRows+4,2) = "M"

ac_Stru(nRows+4,3) = 10

ac_Stru(nRows+4,4) = 0

 

CREATE CURSOR projtemp FROM ARRAY ac_Stru

      

SELECT query

 

SCAN

  SCATTER MEMVAR MEMO

 

  m.cShortName = ShortNme(Name)

  m.cDateTime  = TStmp2Dt(TimeStamp, "DATETIME")

  m.mNotes     = MemoCreateFN()

  

  INSERT INTO projtemp FROM MEMVAR

ENDSCAN

 

USE IN query    &&  Closes temporary query

 

SELECT * ;

  FROM projtemp ;

  ORDER BY    Type, cShortName ;

  INTO CURSOR query

 

RETURN

Now the project lister includes information that can be very handy for those individuals who don’t make regular backups of their project files. I happened to be one of those people who truly believed that if I ever lost a project file it was simple to rebuild by creating a new project file, adding the main program, and rebuilding it. This is true to a point. It only takes losing a project once to realize that this is not as simple as it seems. FoxPro will do a great job locating all the files included in an application, but it is not intelligent to remember which screens had a modal setting, which one defines windows, which one opened files, and so on. Printing off this information from the project is not a great replacement for good backups, but it does provide a start to some handy technical documentation. If your backups are all bad (who always verifies and trusts their backups), this handy reference information can assist you in restoring your screen settings quickly.

You can quickly generate a report that prints out the information to be used as technical documentation for you application. If you output the information to a file you can merge it into an existing technical document in your favorite word processor. Here is quick report example:

Type  File Name        Date

 D     PLISTHLP.DBF    07/09/94 09:44:46

 H     PROJLIST.PJX    07/09/94 09:46:32

 P     MAINPLTS.PRG    06/26/94 22:39:20

 R     HELPPLTR.FRX    06/04/94 16:20:46

 R     PJ01PLTR.FRX    06/04/94 14:23:04

 S     ABOTPLTS.SPR    06/04/94 16:21:02

 S     HELPPLTS.SPR    07/09/94 09:46:32

 S     PARMPLTS.SPR    06/13/94 23:48:44

 s     ABOTPLTS.SCX    06/04/94 16:16:22

 s     HELPPLTS.SCX    07/09/94 09:45:56

 s     PARMPLTS.SCX    06/13/94 23:48:18

 x     PROJECT.BMP     01/18/93 02:50:00

 x     PROJECT.ICO     09/28/93 02:50:00

The Rest of the News...

The rest of the objects in the project file are pretty straight forward. MAINPROG determines if either a program, screen program, menu, or query object is the main program for the application. All objects except for project header and screen sets are either included or excluded from the project based on the setting of the EXCLUDE logical. This determines if they are built into the .APP or .EXE files. For the most part the majority of the objects only use the NAME, TYPE, TIMESTAMP, and EXCLUDE fields. I have not thourghly researched the OBJREV, COMMANDS, SYMBOLS, and OBJECT fields so I cannot discuss them at this time, but most of the objects within a project utilize these fields.

The following table is a complete list of objects maintained within a project file:

Types Objects
H Header
s Screen tables
S Screen Programs
P Programs
M Menus
Q Queries
R Report Forms
B Labels
L Libraries
F Formats
D Tables
I Indexes
X Files
Z Applications

Project Lister Exploits the Project File.

I have written a utility application that uses some of these concepts discussed in this article. The Project Lister v1.2 (included on the companion disk and found in the FoxForum Lib 2 Cross-Platform) provides a FoxPro developer with a listing of all the different objects in the selected project (screens, reports, labels, programs, queries, menus, files, libraries, etc.). It also provides details such as the date and time stamp on the file, the full directory where it is located, and details about the project file and screens. It also provides the English name for the TYPE field so you do not need to remember the TYPE character values. This program was originally designed to provide a checklist for the developer when they needed to review all the files in a project, but it can be a very basic start to some technical documentation, or recovery information when a project is corrupted (and no backup). There is full on-line documentation which can be printed out as well. The output can be sent to the printer, previewed on screen, dumped to a file, or reviewed in a browse window.

At press time version 2.0 has entered beta testing. This release will allow output to be directed to the platform clipboard and to a FoxPro table (.DBF). The original report has bitmaps now printed for the different object types. There is a new report that gives the user selection on the way the objects are sorted (either by object and name or by name only), and the application has been made more “data driven” and modular. When the update is complete I will pass along a copy to FoxTalk to be incorporated on a future release of a companion disk and of course on CompuServe.

Conclusion

Allow your imagination to run wild. Since Microsoft has made the project architecture open (in the form of a database), developers can exploit the file. Several third party developers have products that utilize this open architecture concept to make a living. My examples were simple. A developer can write a complicated application that generates a project, literally building the project file, or a simple one like mine that documents the objects.

The project file as well as the screen, report, and menu files are documented in the Developer’s Guide Appendix A. The concept of the extracting information for documenting pieces of the project and the components of an application can be extended to these files as well. I guess this is a good topic for another article.

This site is designed to be viewed in 800x600 video resolution or higher, but it should work fairly well at any resolution and with any of the major browsers (all free!). Optimized for MS Internet Explorer, Firefox, and Opera (mostly works with Mozilla and Netscape Navigator).

Copyrighted 1998-2005 Richard A. Schummer
All Rights Reserved Worldwide
This page was last updated on 02-Apr-2005