Consultancy and Programming
Advice, tips, techniques and downloads for Visual Foxpro developers.
This article applies to Visual Foxpro 8.0 and earlier. If you are using a later version, please refer to the note at the end of the article.
You probably know that, when designing a Visual FoxPro report, you can select the page size, orientation and paper source from the Print Setup dialog. This is the dialog you reach when you choose File / Page Setup and then click on the Print Setup button within the report designer.
But there's a snag. If you make any changes to the print settings in this way, your users will not be able to override them at run time.
For example, if you set the paper source to "Upper tray", the report will always try to select that tray. You cannot use the REPORT FORM ... PROMPT command to override it at run time, because the PROMPT dialog does not include a setting for the paper source. (But you can use the PROMPT dialog to select a different printer.)
Nor will SYS(1037) help. Normally, that function displays the Page Setup dialog and lets the user change the settings within it. The changes will then affect all printed output for the current session. But if you changed any of the default page settings within the report designer, the SYS(1037) dialog will have no effect on that report. You cannot even use it to send the report to a different printer.
Fortunately, there is a workaround. It involves a little gentle hacking of the report file.
As you might know, the internal format of a VFP report file - that is, the FRX file - is the same as that of a DBF. It follows that you can open the file just as if it was a FoxPro table. You can also browse it and edit it. Now, you don't need us to tell you that editing a report file in this way is hazardous. If you changed the wrong field to the wrong value, you could ruin your carefully designed layout. So take care with what follows - and be sure you have a backup before you start.
The first step is to get rid of the printer settings which were saved in the report designer. To do so, open and browse the report from the Command window. For example, if the report is called Customer, type the following:
USE Customer.frx BROWSE
In the Browse window, look for a record where the Objtype field is set to 1 and the Objcode to 53 (it is usually the first record). In this record, look for the Expr, Tag and Tag2 fields. These are memo fields which contain the settings you made in the report designer's Print Setup dialog. Tag and Tag2 contain binary values. Expr contains plain text, which will look something like this:
DRIVER=WINSPOOL DEVICE=HP LaserJet 6P/6MP - Enhanced OUTPUT=LPT1: ORIENTATION=0 PAPERSIZE=9 PAPERLENGTH=2794 PAPERWIDTH=2159 COPIES=1 DEFAULTSOURCE=4 PRINTQUALITY=-4 COLOR=2
Now, go ahead and delete the contents of these three memo fields. This will put all the saved settings back to their defaults. If you want to let the user pick the page size, paper source or orientation at run time, you can now call SYS(1037) to do the job.
But what if you want to let the user change some of the settings but not others? Or you want to store non-default settings in the report, but you want to let the user override them in certain circumstances? Calling SYS(1037) won't help, because it is all-or-nothing. You can't use it to let the user change some settings but prevent them from changing others. In any case, the function won't work if you have made any changes at all to the settings within the report designer - even if they are different from the ones you want to let the user adjust.
Here's what you do. Let's suppose that you always want the report to be printed in landscape orientation on A5 paper, but you want to let the user toggle the paper source between "Manual feed" and "Lower bin".
Start by selecting the orientation and page size in the Print Setup dialog in the report designer. While you're there, set the paper source to whatever you want the default to be. Save the report as usual.
In your application, give the user a mechanism for toggling the paper source. This could be a command button, a check box, a menu command or whatever. When the user makes the choice, execute code similar to the following:
USE Customer.frx LOCATE FOR Objtype = 1 AND Objcode = 53 REPLACE Tag WITH "" REPLACE Tag2 WITH "" IF "DEFAULTSOURCE=2" $ Expr lcNew = "DEFAULTSOURCE=4" lcOld = "DEFAULTSOURCE=2" ELSE lcNew = "DEFAULTSOURCE=2" lcOld = "DEFAULTSOURCE=4" ENDIF REPLACE expr WITH STRTRAN(Expr,lcOld,lcNew) USE
The next time the report is printed, it will select whichever paper source the user chose.
Here's what the code does. First, it opens the report file as a table and locates the record containing the settings. It then deletes the binary values of the settings. That's no problem - the report will run fine without them.
Next, it checks the existing setting of the paper source. If it is 2, it changes it to 4 and vice versa. As you might guess, this setting is specified by the DEFAULTSOURCE value: 4 means "Manual feed", 2 is "Lower bin". Finally, the Expr field is updated with the changed value and the file is closed.
How did we know what values to use for DEFAULTSOURCE? From the help screen for the PrtInfo() function. The PrtInfo() function, which returns the settings for the current printer, uses the same values as the Expr field. So if you want to understand the contents of the field, that's where to look.
A final word: When you distribute your application, be sure to exclude the FRX file, and its associated FRT file, from the build. In other words, do not bind these two files into the EXE file. If you did, the above code would not be able to update the files and your user would see a run-time error. Instead, just give the user a free-standing copy of the two files.
In VFP 9.0, the whole question of printer settings in report files has become very much easier. In fact, you'll never need to hack the FRX file in the way described in this article. By default, printer settings are no longer saved in the FRX. Regardless of what settings were in force at report design time, you can use SET PRINTER TO NAME or SYS(1037) to establish run-time settings.
If you want to override the default behaviour - that is, if you do want to save the report settings in the FRX - open the Report menu in the report designer, and select the Printer Environment option. You might do this if you want to force a report to be printed on a particular printer, for example. If you want the printer settings to be saved in all reports by default, go to Tools / Options / Reports, and enable the 'Save printer environment' option.
Mike Lewis Consultants Ltd. April 2000. Revised January 2006.
FoxStuff is maintained by Mike Lewis Consultants Ltd. as a service to the VFP community. Feel free to download and use any code or components, and to pass around copies of the articles (but please do not remove our copyright notices or disclaimers).
The information given on this site has been carefully checked and is believed to be correct, but no legal liability can be accepted for its use. Do not use code, components or techniques unless you are satisfied that they will work correctly in your applications.
© Copyright Mike Lewis Consultants Ltd.