Running XFRX
Running XFRX in VFP 5.0, 6.0, 7.0 and 8.0
Please note
To make the text easier to read, the differences between XFRX for VFP 5.0, 6.0, 7.0, 8.0 and XFRX for VFP 9.0 are further in the text described as differences between VFP 8.0 and VFP 9.0. If VFP 8.0 is mentioned, the described feature applies for VFP 5.0, 6.0 and 7.0 as well.
Call XFRX with "XFRX#INIT" as a parameter to obtain the XFRXSession object:
LOCAL m.loSession m.loSession=XFRX("XFRX#INIT")
- Call SetParams method to set the document generation parameters. (Please see page 80 for details and full parameter list).
- If SetParams return 0 (zero), call ProcessReport method for each report to process. (Please see ProcessReport description for details and full parameter list).
- After all reports are processed, call Finalize method to finish the document generation process.
- You can also call ResetPageNo() method if you need to reset the page number in between reports.
Example 1
This code merges two reports – report1 and report2 – into a single PDF document, output.pdf
USE demoreps\invoices ORDER customer LOCAL m.loSession, m.lnRetval m.loSession= xfrx("XFRX#INIT") m.lnRetVal = m.loSession.SetParams("output.pdf",,,,,,"PDF") IF m.lnRetVal = 0 m.loSession.ProcessReport("report1") m.loSession.ProcessReport("report2") m.loSession.finalize() ELSE ? m.lnRetVal, m.loSession.ErrorMessage(m.lnRetVal) ENDIF
Running XFRX in VFP 9.0
In VFP 9.0, the standard object-assisted mode is used to run XFRX:
Call XFRX.APP with "XFRX#LISTENER" as a parameter to obtain the XFRXListener object:
loListener=XFRX("XFRX#LISTENER")
- Now there are two options you can choose from:
- Call loListener’s SetParams method that has exactly the same parameters and return values as the one in XFRXSession class. (Please see page 80 for details and full parameter list).
- Or, you can fill in individual properties of loListener and run SetParams method without any parameters to make sure you can proceed to the next step. (Please see page 90 for full list of properties available).
- Call the native REPORT FORM command with the new OBJECT clause for each report to process. If more reports are merged, include NOPAGEEJECT clause with each REPORT FORM call but the last one.
- Alternatively, you can leave the NOPAGEEJECT clause in the last REPORT FORM command as well (which may be useful is some scenarios) and call loListener.Finalize() to finish the document generation.
Wrapper
XFRX#LISTENER is wraper between VFP report listener and XFRX Core. XFRX ignore all changes created by GDIPlusGraphics or SharedGDIPlusGraphics handle.
Note
Even in VFP 9.0, you can initialize the XFRXSession class via “XFRX#INIT” parameter and use the XFRX’s own engine, rather than the native one.
The following examples all do exactly the same (and they also do exactly the same as the example 1 above), showing various ways of calling XFRX in VFP 9.0:
Example 2
USE demoreps\invoices ORDER customer LOCAL m.loSession, m.lnRetval m.loSession = XFRX("XFRX#LISTENER") m.lnRetval = loSession.SetParams("output.pdf",,,,,,"PDF") IF m.lnRetval = 0 REPORT FORM report1 OBJECT m.loSession NOPAGEEJECT REPORT FORM report2 OBJECT m.loSession ELSE ? m.lnRetval, m.loSession.ErrorMessage(m.lnRetVal) ENDIF
Example 3
USE demoreps\invoices ORDER customer LOCAL m.loSession, m.lnRetval m.loSession = XFRX("XFRX#LISTENER") m.lnRetval = m.loSession.SetParams("output.pdf",,,,,,"PDF") IF m.lnRetval = 0 REPORT FORM report1 OBJECT m.loSession NOPAGEEJECT REPORT FORM report2 OBJECT m.loSession NOPAGEEJECT m.loSession.finalize() ELSE ? m.lnRetval, m.loSession.ErrorMessage(m.lnRetVal) ENDIF
Example 4
USE demoreps\invoices ORDER customer LOCAL m.loSession, m.lnRetval m.loSession = XFRX("XFRX#LISTENER") m.loSession.targetType = "PDF" m.loSession.targetFileName = "output.pdf" m.lnRetval = m.loSession.SetParams() IF m.lnRetval = 0 REPORT FORM report1 OBJECT m.loSession NOPAGEEJECT REPORT FORM report2 OBJECT m.loSession ELSE ? m.lnRetval, m.loSession.ErrorMessage(m.lnRetVal) ENDIF
XFRX#LISTENER supports TYPE
This feature is from XFRX 24.0
Calls XFRX with some parameter create general object oXFRX on _Screen object. If is parameter "LOADRL", then XFRX load report listeners for all lnows outputs.
Output | Type HEX | Type DEC |
---|---|---|
DOC | 0x800 | 2048 |
RTF | 0x801 | 2049 |
NATIVE_DOCX | 0x802 | 2050 |
ODT | 0x803 | 2051 |
ODS | 0x804 | 2052 |
HTML | 0x805 | 2053 |
MHT | 0x806 | 2054 |
0x807 | 2055 | |
XPS | 0x808 | 2056 |
PLAIN | 0x809 | 2057 |
CPLAIN | 0x80A | 2058 |
FDOC | 0x810 | 2064 |
FRTF | 0x812 | 2065 |
NATIVE_FDOCX | 0x813 | 2066 |
FODT | 0x814 | 2067 |
XLS | 0x820 | 2080 |
XLSPLAIN | 0x821 | 2081 |
NATIVE_FXLSX | 0x822 | 2082 |
NATIVE_PFXLSX | 0x823 | 2083 |
FODS | 0x824 | 2084 |
PFODS | 0x825 | 2085 |
TIFF | 0x830 | 2096 |
PNG | 0x831 | 2097 |
JPEG | 0x832 | 2098 |
EMF | 0x833 | 2099 |
BMP | 0x834 | 2100 |
GIF | 0x835 | 2101 |
XFF | 0x840 | 2112 |
XML | 0x841 | 2113 |
LOCAL m.llPreview, m.llPRINT, m.liTYPE *=EVALUATE([xfrx("XFRX_INIT")]) && Initialize oXFRX object =EVALUATE([xfrx("LOADRL")]) && Initialize oXFRX object and load report listeners WITH _Screen.oXFRX *m.liTYPE=.GetRL("XFF") && for PRINT or PREVIEW m.liTYPE=.GetRL("PDF") && 0x807, 2055 *.SetPDFA(.T.,"3a") *.AddAttachment("file.txt",.T.) *.DigitalSignature("testeqeus.pfx","xxxx",3, "testing name", "testing contact info", "testing location", "testing reason") *.SetPasswords("owner","user") *.SetTextToImage("ALL") *.WATERMARK.Set(1) *.WATERMARK.SetText("watermark W A T E R watermark",,.t.) *.WATERMARK.SetColor(RGBA(0,0,0, 128), RGBA(0,0,255, 50)) *.WATERMARK.Setorientation("diagonal") *.WATERMARK.lDrawCross=.T. *.WATERMARK.lDrawRectangle=.T. *.SetOtherParams("DONOTZIPTEXTSTREAM", .T.) && for development *.setOtherParams("DEVELOP", .T.) *.setOtherParams("DEVELOPFOLDER", "c:\temp\xfrxdev\") *.SetArchive(laOuts(lii,2)+".zip") *m.loScripts = createobject("myXFRXScripts") *.registerScript(loScripts, "drawWaterMark", 1,"ALL",0) && on each page ENDWITH SET CLASSLIB TO xfrxlib\xfrxlib ADDITIVE DO CASE CASE m.llPreview REPORT FORM report1 OBJECT TYPE m.liTYPE NOPAGEEJECT PREVIEW REPORT FORM report2 OBJECT TYPE m.liTYPE CASE m.llPRINT REPORT FORM report1 OBJECT TYPE m.liTYPE NOPAGEEJECT TO PRINTER REPORT FORM report2 OBJECT TYPE m.liTYPE OTHERWISE REPORT FORM report1 OBJECT TYPE m.liTYPE NOPAGEEJECT TO FILE ("output.pdf") REPORT FORM report2 OBJECT TYPE m.liTYPE ENDCASE
Using THISFORM and THIS references
Note
This paragraph applies to VFP 8.0 only. THISFORM and THIS references are handled properly by the native report engine in VFP 9.0.
XFRX supports THISFORM and THIS in the report field expressions. However, being a normal VFP application, XFRX cannot access THISFORM and THIS objects directly. Instead, THISFORM object has to be explicitly sent to XFRX via setThisform() method, THIS needs to be sent via setThis() method. If you have THISFORM in your report, call xfrxSession.setThisform(THISFORM)
before calling ProcessReport(). If you are using THIS, call xfrxSession.setThis(THIS)
.
GDI+ compatible word wrapping algorithm
Since the introduction of VFP 9.0 we are experiencing layout compatibility issues between the old reporting engine (pre-VFP 9.0) and the new reporting engine (VFP 9.0). Please see Guide to Reporting Improvements VFP 9.0 help topic for more information.
With XFRX we are experiencing a similar problem - while the pre-VFP 9.0 report engine inside XFRX is using GDI for wordwrapping and layout calculation, the VFP 9.0 report that is used in XFRX for VFP 9.0 is using GDI+. Moreover, XFRX is using GDI+ for printing, output to pictures and previewing. The main difference between using GDI and GDI+ is text width. Each text element is slightly wider with GDI+, which can result in element content being cut, earlier wrapping longer stretched fields. Here is a summary:
XFRX ver. 12.3 and earlier | ||
VFP 9.0 | VFP 8.0 and earlier | |
Output to PDF and other output formats | GDI | GDI |
Report engine | GDI+ | GDI |
Report previewer | GDI+ | GDI+ |
Printing out of XFRX | GDI+ | GDI+ |
Although converting everything to GDI+ would ease the complexity, it would bring another problem - "old" reports might need to be modified, see Changes in Functionality for the Current Release VFP 9.0 help topic for more information. So, instead, the latest XFRX version now contains both GDI and GDI+ wordwrapping algorithms and you can choose which one is going to be used. By default GDI+ is used in VFP 9.0 in the listener mode and GDI is used in VFP 8.0 earlier. There is probably no reason to switch to GDI in VFP 9.0 but it might sometimes be useful to switch to GDI+ as printing and previewing is still in GDI+:
XFRX ver. 12.4 with wordwrapping set to GDI+ | ||
VFP 9.0 | VFP 8.0 and earlier | |
Output to PDF and other output formats | GDI+ | GDI+ |
Report engine | GDI+ | GDI+ |
Report previewer | GDI+ | GDI+ |
Printing out of XFRX | GDI+ | GDI+ |
XFRX ver. 12.4 with wordwrapping set to GDI | ||
VFP 9.0 | VFP 8.0 and earlier | |
Output to PDF and other output formats | GDI | GDI |
Report engine | GDI+ | GDI |
Report previewer | GDI+ | GDI+ |
Printing out of XFRX | GDI+ | GDI+ |
To set the wordwrapping algorithm manually then, before running your reports, create a public or private variable _xfrx_WordWrapAlgorithm and set it to 1 for GDI mode and 2 for GDI+ mode.
Text output trimming
In VFP 9.0 the trim mode is controlled by the "Trim mode for character expressions" setting on the "Format" tab in the "Field Properties" form.
In pre-VFP 9.0 version the trimming is controlled by a special string in fields comment: #UR TRIM=, followed by the trim mode code:
Code | Description |
0 | Default trimming in pre-VFP 9.0 versions - trim to nearest word |
1 | Trim to nearest character |
2 | Trim to nearest word |
3 | Trim to nearest character, append ellipsis |
4 | Trim to nearest word, append ellipsis |
5 | Show inner path as ellipsis |
Example: #UR TRIM=3 wraps to the nearest character and appends ellipsis
Displaying progress bar in VFP 8.0
XFRX provides a simple hook so that any progress bar tool could be used for displaying the progress during the document generation process. All you have to do is to create an object which contains updateProgress() method and pass it to XFRX. During the generation process, XFRX calls updateProgress() method either after each page or after each record is processed.
This is a simple example of displaying the generation progress in a wait window:
LOCAL m.loSession, m.loProgress, m.lnRetVal m.loSession=xfrx("XFRX#Init") m.loProgress = CREATEOBJECT("progress") m.lnRetVal = m.loSession.SetParams("document",,,,,,"PDF") IF m.lnRetVal = 0 m.loSession.setProgressObj(loProgress,2) m.loSession.ProcessReport("myReport") m.loSession.finalize() ELSE ? m.lnRetval, m.loSession.ErrorMessage(m.lnRetVal) ENDIF DEFINE CLASS progress AS CUSTOM PROCEDURE updateProgress LPARAM m.ta, m.tb, m.tc WAIT WINDOW NOWAIT "Page #: "+allt(str(m.tb))+" Report #: "+allt(str(m.ta))+" ("+allt(str(m.tc))+"%)" ENDPROC ENDDEF
The progress object is attached to XFRX with setProgressObj() method. This method takes two parameteres - the first one is the progress object, the second defines the information the updateProgress() will be getting. It can contain two values: 1 - only page number and report number will be provided in updateProgress() method, or 2 - page number, report number and percentage progress within the current report will be provided. Using the percentage progress information is more accurate and more suitable for progress bar visualization, but to provide this, XFRX has to calculate the number of records in the processed table, which, sometimes, can be very time demanding. In this cases, 1 can be used not to calculate the number of records.
The updateProgress method takes three parameteres: current report number, current page number and actual percentage progress within the current report.
Displaying progress bar in VFP 9.0
In VFP 9.0, the XFRXListener object can be chained together with another listener which would take care of the progress bar displaying. One of the possible ways to do this is to use the UpdateListener class, which is shipped with VFP 9.0, in FFC.
Example:
This sample code creates an instance of the UpdateListener class and chains it with XFRXListener:
LOCAL m.loSession, m.loUpdate m.loSession = XFRX("XFRX#LISTENER") SET CLASSLIB TO (HOME()+"FFC\_reportlistener.vcx") m.loUpdate = CREATEOBJECT("updatelistener") m.loUpdate.thermFormCaption = "Report in progress ..." m.loSession.successor = m.loUpdate m.lnRetval = m.loSession.setparams("output.pdf",,,,,,"PDF") IF lnRetval == 0 REPORT FORM (m.lcReportName) OBJECT loSession NOPAGEEJECT m.loSession.finalize() ELSE ? m.lnRetval ENDIF
Canceling report generation in progress
Note
This paragraph applies both to VFP 9.0 and VFP 8.0
The report generation process in progress can be canceled by setting the global variable gnStopXFRX to 1. For example, you can, for example, use it this way:
ON KEY LABEL Ctrl+C gnStopXFRX = 1
Printing page ranges
Note: This paragraph applies to VFP 8 only. In VFP 9.0, please use the RANGE clause of the REPORT FORM command to achieve the same.
To define the page range, call setPageRange() method before calling calling ProcessReport(). There are two possible ways how to call the setPageRange() method:
setPageRange(tnFrom, tnTo)
tnFrom and tnTo define the from-to range. If tnTo is empty, the total number of pages is used
Example:m.loSession.setPageRange(5,10)
- setPageRange(tcRange)
tcRange is a string, which can contain page numbers and page ranges delimited by commas, the page range is defined as "from-to".
Example:m.loSession.setPageRange("1,4,10-20,25")
User-defined page size
Note
This paragraph applies both to VFP 80. and VFP 9.0
You can define the page size of the generated document. The user-defined page size will override the page size stored in the report. To define the user-defined page size, call setPaperSize() method with paper width and paper height as parameters:
setPaperSize(nUDPaperWidth, nUDPaperHeight)
The unit is Inch * 10000.
See also: HTML page size adjustment.
Zipping the generated files
Note
This paragraph applies both to VFP 8.0 and VFP 9.0
The generated file can be automatically zipped. This feature is controlled by the last three parameters of SetParams() method of XFRXSession and XFRXListener classes or, with an equivalent behavior, by the three parameters of ZipDocument() method of XFRXListener class.
Example:
With the following SetParams parameters, XFRX first creates "invoices.pdf", then creates "archive.zip" (if it doesn't exist) and adds "invoices.pdf" into the archive. Then the original "invoices.pdf" will be deleted:
m.loSession.SetParams("invoices.pdf",,.T.,,,,"PDF","archive.zip", .t., .t.)
Old multiline behavior
XFRX 15.0.3 fixes a bug with a wrong multiline height calculation - the object height does not equal with object height in VFP native preview. if you need the previous multiline height calculation set the lOldMultiLineBehavior property to true.
m.loSession.lOldMultiLineBehavior = .T.
XFRX#INIT and multiband support
If you have a report with multiple detail bands and you need to run it in the pre-VFP9 calling syntax (eg. you need export a report in your dll application), set lMultiDetailBehavior property on. This feature is experimental.
This property is obsolete since XFRX 17.0. XFRX 17.0 support multiple detail bands.
m.loSession.MultiDetailBehavior = .T.
XFRX#LISTENER and PREVIEW (XFRX 15.3)
Supports for PREVIEW clause for XFRX#LISTENER in REPORT command.
Simply way:
LOCAL m.loSession, m.lnRetVal SET CLASSLIB TO (HOME()+"ffc\_reportlistener") ADDITIVE SET CLASSLIB TO xfrxlib\xfrxlib ADDITIVE m.loSession=EVALUATE([XFRX("XFRX#LISTENER")]) m.lnRetVal = m.loSession.SetParams(,, ,,,,"PREVIEWFRM") IF m.lnRetVal = 0 REPORT FORM (lcPath+"_reports\test") OBJECT m.loSession PREVIEW ELSE ?m.loSession.ErrorMessage(m.lnRetVal) ENDIF
Creates form previewer:
LOCAL m.loSession, m.lnRetVal SET CLASSLIB TO (HOME()+"ffc\_reportlistener") ADDITIVE SET CLASSLIB TO xfrxlib\xfrxlib ADDITIVE m.loSession=EVALUATE([XFRX("XFRX#LISTENER")]) m.lnRetVal = m.loSession.SetParams(,, ,,,,"PREVIEWFRM") IF m.lnRetVal = 0 m.loSession.oPreviewFRM = CREATEOBJECT("frmMPPreviewer") m.loSession.oPreviewFRM.WindowType=0 && or another settings REPORT FORM (lcPath+"_reports\test") object m.loSession PREVIEW ELSE ?m.loSession.ErrorMessage(m.lnRetVal) ENDIF
Running XFRX in MTDLL
Please, read informations about PROGCACHE key in "Special Terms for Configuration Files" Visual FoxPro Help.
Don't use default value (-2). XFRX is behaves strangely for the value - error 1202, cx00000005, etc.