C&L Nicholls - Spacefold     Lisa's Page     >L<'s Fox Stuff     FoxSpoken Volume Index

   FoxSpoken Volume 1

articles on this page retired Apr.97

Before you use this material, please be sure you have read and understand the various provisos *3 with which I provide it for your use.

Contents of this page:

  2. Class Browser add-on for #INCLUDE files
  3. PARSER: ways to parse and execute code
  4. The Whipped Tip Dept: Editor Comment Strings
  5. CLASSDOC: class-dependency diagramming utility
  6. Grid Partitions? Please... Just say no
  7. AppWiz: a place to start your frame-work?


Pertinent files: GENMENUL.ZIP updated Jan.97, ~25k. A separate text file, GENMENUL.TXT ~4k, is available if you want more information about AUTOVER/GENMENU before downloading. This text file is included in the .ZIP.

Rejoice. Microsoft have uploaded a replacement GENMENU file, improved over the version of GENMENU that shipped with 5.0 (check it out on the MS site).

The new version eliminates a number of bugs, especially some that affect top form menus. Ever try to figure out why your top form menus don't Append as they should? Or why they behave so badly with multiple top form menus? Or why your system pads sometimes deliver 'blank popups' after you use a top form menu? Or why your Setup and Cleanup didn't get generated properly? The new GENMENU -- and the more flexible arguments you can use when you DO the.MPR -- will help you out. You'll want to study the comments at the top of an .MPR, to understand how to call the new-style MPRs with extra arguments.

MC Framework people and others have been using my hacked version of GENMENU, GENMENUL, for some time. At various stages GENMENUL has included quite a few improvements over the standard GENMENU -- I think the MAChete book had the most elaborate version -- but at this stage GENMENUL for 5.0 includes only one addition that we've found critical to development. This is AUTOVER, a technique pioneered by Matt Peirse. AUTOVER forces certain extra processing to take place during every project build by using a special, self-editing menu.

As its name suggests, the original purpose of AUTOVER in Matt's version was to force the Project Build process to auto-increment an application build number. My version allows you to add any additional BUILD APP processing you'd like to the special menu, but the build-numbering is the one extra GENMENU feature that we couldn't live without. Naturally, MC Framework is 'AUTOVER-aware', and makes good use of your build information if you make an AUTOVER-type menu available to an MC controller object.

MC doesn't mandate GENMENUL or AUTOVER use. However, the next MC upload will include code that assumes the new GENMENU you can get from Microsoft or the new GENMENUL you can download here. That's because a good many of the current MC changes will be topform-related; the new GENMENU means I can remove some of the worst MC workarounds, in the form classes as well as the MC template menus, and plan a better topform strategy overall.

Whether you use MC or not, you owe it to yourselves to download one of the new GENMENUs, and you have no reason to wait!

By request, and with permission from >L< and Matt, Andrew Ross MacNeill added AUTOVER and several other Cornerstone menu techniques to his groundbreaking GENMENUX program in the 2.6-3.0 time period. (Check out the SKIP_REDIRECT generator directive, for example.) I'll probably add these back into GENMENUL when I have time, but no promises. If you're a GENMENUX user, you'll want to check with Andrew to see if he's updated GENMENUX for the topform changes.


Class Browser Add-On for #INCLUDE files

Pertinent files: ADDINCL.ZIP updated Apr.97 to fix bug with member objects, ~10k. A text file from this .ZIP, ADDINCL.TXT ~3k, is also available for viewing before download if you wish.

If you've never written an AddOn for the Class Browser, you might want this file just to see how you might create and install such a thing.

If you've ever changed a .H (header) filename or location, and then cursed because you realized that you were going to have to edit a bunch of classes to know where their Include Files were, now you can do this through the Class Browser interface.

BTW, I don't know if it is still a problem in 5.0, but you could run into major problems in 3.0 if you tried to save changes in the Class Designer or Form Designer for a class whose Include File was open in Notepad someplace. If you've had GPFs when saving a class and don't know why, this could be the reason: Fox tries to do the compile, et voilą.


PARSER: parsing and executing code at runtime

Pertinent file: PARSER.TXT, ~3k, is all you need. I've placed it here in text form so you can refer to the limited code while you read this page, but, once downloaded, you only need to rename it to a PRG to have runnable code.

This keeps coming up on line: How can I create new lines of code dynamically at runtime, and then execute them?

There are two main ways this can be done:

  1. You can place all the lines of code into a PRG on disk, which can be compiled and executed like any other program, or
  2. You can macro-expand the code, line by line, for execution.

The first method is generally a better choice, IMHO. It's fast, because it makes Fox do all the work. You don't have to struggle with evaluation of structures and conditional logic which should force lines to be omitted or repeated. (There are quite a number of such constructs in VFP.) You can add separate procedures as necessary.

Think about it: this is how a lot of your internal Fox work is getting done, and how much of the work your Inet applets, MS Office, and half the rest of the world do their work too. A temporary file is created and then things happen to it. The application that creates the temporary file has several responsibilities, such as keeping track of a unique name for this file, deciding on a reasonable location for it, and cleaning it up when work is completed.

Incidentally, for the purposes of appropriate file cleanup, you may be interested to know that the Fox ERASE command is NORECYCLE by default. This keyword is undocumented, but may still be added to your ERASE command line, to emphasize the fact that the ERASEd file will not be placed in your Recycle Bin. The opposite keyword, RECYCLE, which is documented, will place ERASEd documents into the Trash, er, Recycle Bin when appropriate.

If you download GENMENUL.PRG, you'll have a perfect example of this technique, including appropriate error-handling. (Look at the code I added in the BuildEnable() procedure, which runs code in the Comments field of a special MNX record.) In GENMENUL, I'm working from a memo field, but your code could be TEXTMERGEd directly to a PRG at runtime, or the PRG could be created in many other ways.

I am not sure why people think that creation of a temporary file and running it in this manner is a bad idea. The only down-side I can imagine is that you can't use it under the runtime libraries. The most significant difference between the full product and a distributed application that runs under the runtime libraries is that the latter cannot compile code.

If you need to use your dynamic code-creation-and-execution method under the runtime, you're stuck with the second method: parsing and macro-expanding code, which does not require compilation. PARSER shows you how I do that.

PARSER is unusual in that it puts all the code into an array of lines, RETURNing this array to a calling program that passed the array by reference. (In other ways, PARSER may only be 'unusual' in a little extra niceness of attention to concatenation and comment types -- does anybody really use NOTE anymore??)

I use this method because the outer program can then look at the results and decide whether further evaluation is required. For example, the outer program would be responsible for handling loops' duration and scope, if you need such constructions.

I don't really require dynamically-created code that includes loops, but my sample call for PARSER, shown as notes at the end of the file, gives you another reason I do require some extra evaluation outside PARSER. If you feel sure nothing like this could ever happen to you, feel free to adapt PARSER to execute each line of code as it parses the line rather than passing the array.

If you need to parse text strings for this use or for any other reason in Fox, you should take particularly note of the _MLINE system variable used in this code, probably the most generally valuable part of this example. _MLINE is a system-maintained offset that can significantly speed up your work parsing large text strings.


The Whipped Tip Dept: Editor Comment Strings

I try to be ladylike, really I do. And I SWORE (in a very ladylike manner, naturally) that I was not going to publish trivial Fox tips on my site, I don't have room or time. But sometimes you just gotta:

The January 97 issue of DBA -- which I note in passing also makes the Pollyannish statement that you 'only need to know a few things to quickly publish databases on the Web' <sigh> -- contains Tamar Granor's piece describing the VFP 5 improvements over 3.0.

I recommend that everyone familiarise his or her self with the differences between the releases, and this article is certainly one place you could start.

However, Dr. Granor suggests that 'control over the... comment strings' would be an 'extremely useful enhancement'. She'd be absolutely correct, except that it's already in the product! I suppose if we emended her statement to say that 'control available through the standard UI' would be 'a small enhancment', it would be correct -- but the functionality you want and need, which is the main event, is IN THE PRODUCT, folks, so don't get the wrong idea.

Here's how real Fox programmers can take control of their comment strings, until such time as the 'small and relatively trivial enhancement' of a Tools Options dialog entry (or whatever) is available:

Not surprisingly, you edit the Windows Registry (use REGEDIT). The key you want is:

My Computer\HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro\5.0\Options\EditorCommentString
You probably won't find it in there by default; I had to add it. Use the comment string you want as the value data for this key, obviously.

Anybody at the opening session at the October Fox DevCon would have known this was possible, since this little feature was very much in evidence during Calvin's demo. I don't know what DBA's lead time is, to be fair, but I think this key went into the registry fairly early in the 5.0 beta. I'm sure you're going to want to start using it before the next release <g>.


The Teaching Your Grandma To Suck Eggs Dept (CLASSDOC)

Pertinent files:CLASSDOC.ZIP updated Jan.97, ~13k If you wish some additional information about CLASSDOC before download, you can read CLASSDOC.TXT ~11k, a text file from the .ZIP -- but as you see it's almost as big as the .ZIP file!

In much the same vein as The Whipped Tip, somebody on microsoft.public.fox.programmer.exchange (check out the msnews.microsoft.com news server*2) recently decided to explain what recursion was to me <sigh>.

I'm uploading CLASSDOC partly to correct any impression that may have resulted from this discussion, and partly to give wider exposure to a tool I've written that (I feel) provides a truly useful example of recursion. It also uses the treeview control -- another item that seems to give people fits -- and provides a good use of the common dialog control, plus some insight into the VCX structure and a bunch of other important techniques.

CLASSDOC was written for one of my private clients, who has graciously consented to my sharing it with you. They needed to explore the dependencies between classes, in a very large class tree. The Class Browser doesn't fit this requirement, because it lets you look at a class' own superclasses, which determine its own inheritance, but can't help you resolve what effects editing a parent class might have on its multitude of descendents.

Looking at the classes within one project doesn't help, either, since your library classes may be used by a multitude of projects. You'll want to know what effects any change will have on all of them.

So CLASSDOC asks you to determine a "baseclass library". This is the VCX that contains the classes you may want to edit. CLASSDOC will then check the VCXs in the same folder, and as many other folders as you would like to add, for other classes that depend on your chosen "baseclass VCX".

The current CLASSDOC family of classes provides its output in five formats, which include some different levels of detail. To help you organise the current set of options into preferences, the single CLASSDOC.PRG starts with a set of #DEFINEs. To help you see all the different format/output types, CLASSDOC.PRG provides a silly sample program that allows you to choose between the five types every time you run the program (be sure to read the comments so you can turn this off when you're more familiar with the choices), if you continue to use my framing program at all.

You'll note that one of the options available to CLASSDOC is an "add-on" feature, and I've supplied you with a sample (CLASSADD.PRG will give you a count of classes in the VCXs that have been examined and don't inherit from any of the classes in the chosen BASECLASS.VCX).

All of this, and quite a bit more, is contained in the comments and text file that accompany CLASSDOC.PRG. You'll also find information about changes I'd like to make to this class family in the future.

To return to the subject of recursion, it is possible to have corrupted VCX records with empty objname fields. You'll know if this happens because you'll run out of levels in the current program stack -- the recursion will continue endlessly -- and CLASSDOC will terminate abnormally when this happens.

Don't worry about this before it happens (for one thing, there are some records in the VCX that are supposed to have empty objname fields, and they don't cause any problems in CLASSDOC). I'll include some instructions in CLASSDOC.TXT for appropriate cleanup, in case it does happen to you.

The important thing to realise is that VFP's current stack limit (128 nested procedural calls and 384 nested programming structures) is magnificently capable of handling CLASSDOC's requirements. (If your class tree is nested greater than 128 classes deep, something is terribly wrong with your class design <g>.) In fact, I asked the gentleman who lectured me on recursion exactly when he would need a greater limit, and I'm still waiting for an answer <s>.


Grid Partitions: Just Say No

Pertinent files:GRIDLOCK.ZIP updated Jan.97, ~4k The .ZIP file contains a sample form and data -- I don't think you need any additional descriptive information beyond what I've written here.

People keep wondering why partitions don't work as expected in Grids. The short answer is that they didn't work right in BROWSE, either.

Clue #1: Don't make the mistake of thinking that there are more separate pieces inside the two-panel grid object than there actually are. Clue #2: What you really want is BROWSE... LOCK, which hasn't worked right since FoxBase. FoxPro 1.0 faked it in an attempt to remain compatible with DBase III and keep it in the language, along with BROWSE FORMAT, but that's another story.

If you've already had the problem, you know what I am talking about, so I don't need to go into further detail. If you haven't had the problem, it's because your interface requirements are sensible and don't lead you to have any great need for Grid partitions, so (trust me on this) you really don't want to know. Skip to the next section.

The solutions are as difficult to describe without visual aids as the problem is to visualise unless you've had it. So, if you do need this functionality, I've created a little sample to show you how I'd fake it.

All the really meaningful code is in the AfterRowColChange() method of the grid -- you'll see the trick there and in the DataEnvironment.

The only other code is in the editbox's Keypress(), where I made the Ctrl-Up and Ctrl-Down arrows scroll you through the grid, since the grid itself is actually using memo fields and won't scroll properly.

If your 'GRID LOCK' situation really used something other than memo fields for the 'LOCKed' field, you wouldn't have to bother with this; you would just scroll through the grid normally using arrow keys. If your LOCKed field really is a memo field, you could take a cue from this Keypress() code to design a more thorough set of navigation keys.

Scroll bars on the grid have unrelated problems, and cause ifficulties here that are REALLY NOT MY FAULT <g>, so I didn't provide scroll bars in this example grid. If you want scrollbars on this type of grid I would suggest an OCX, either between the two grid 'panels' or to one side. (After all, PanelLink = .F. doesn't really make any sense! And never did. So there would never really be a need for two vertical scroll bars to move the unlinked panels separately.)


A Poor Man's Alternative to Framework Use

You never use Wizards? You haven't checked out the Application Wizard in 5.0? I think you should.

Although I wouldn't use the files it generates as they stand, they are quite amenable to reasonable adaptation because, with all their faults, and limitations as written, they are predicated on sound OO and Fox dev principles. (Translation: This is not your father's TasTrade.)

What's more, you can change the template files from which the Application Wizard generates your application files to suit yourself -- with little effort. I mean, the Wizard makes these files available to you, and it won't take much effort for you to figure out how to get the Wizard to use your versions. I also mean that the template files are clearly-enough written that you shouldn't have much trouble figuring out how they work or what their components do. I don't mean that all the modifications I think you should make will jump right out at you -- sorry, folks, I have to keep some information to myself occasionally -- but you'll probably have your own ideas on this score, anyway.

App Wiz (I just love saying that!) doesn't show up on the Wizards list under the Tools menu. You have to choose 'All' and pick the Application Wizard from the resulting dialog <sigh>.


Lisa Slater Nicholls