Improvements to PDFrun PDF generator.

Topics: Developer Forum, User Forum
Coordinator
Jan 25 at 3:20 PM
Overall I've been very impressed with ActiveVFP. There are a couple of features in the currently available demo which did not work for me. One was the email sender, which I was able to get working using other code from the web. The other is the PDF generator.

The PDF generator (PDFRUN) as it is does work, as long as your form only accesses a single table and does not use any outside variables.

Since PDFRUN is an executable running in its own memory space, it can't see what tables you have open or what variables you have, so you need a way to pass this information over to it somehow. Not only that, if your form calls functions, you need a way to make those functions available to PDFRUN also. And furthermore, my existing database has a method of expanding the reach of the PDF beyond the scope the application extends to it with a program file.

In order to deal with these three issues I made three changes to the source code of PDFRUN, for which I needed to acquire a copy of VFP to recompile it and test/debug it.

I worked on ActiveVFP for over a year without even a copy of VFP so that should tell you how good ActiveVFP really is. This is the only thing I'm sure I needed it for.

Ok, so what changes did I make?

First of all, I had to understand PDFRUN, and during that process I ripped out a lot of unnecessary code and reorganized it and renamed the functions. For example, there is a useless function to install PDF reader. Nevermind that this is running on the web server.

I also use the error string for logging, so I could see ALL the errors. As it is it only reports the LAST error, so it took a while for me to trace my GhostScript issue and get its error code.

There are three new functions which must be called before the report form command:
  1. I require a separate PRG file containing functions which are called inside the form. I don't want to have to add them to the PDFRUN, it doesn't make sense to do so, especially because I don't know what forms might need in the future, and these functions may be used elsewhere in the front end application and may be in a shared PRG file.
cExtPrg="" &&filename of external PRG file containing support functions
function loadSupportFuncs()
if vartype(this.cExtPrg)!="C" or empty(this.cExtPrg)
    return .f.
endif
if !file(this.cExtPrg)
    return .f.
endif
set procedure to (this.cExtPrg) additive
endfunc && loadSupportFuncs
  1. I need to use EXECSCRIPT call inside PDFRUN to perform setup tasks for the form. I tried including functions in here, but it didn't work, so that's why #1 above was needed. EXECSCRIPT can load additional tables, set relations to them, and declare globals/publics before the report form is executed. This set up is constructed as a string and passed as a parameter to oPDF.
Note that I have renamed some of the parameters to be more explicit.

You have to change the path here because the default path is /WINDOWS/SYSTEM32/ which does not have write access. So I also pass my temp path, which I added to oProp in MAIN.PRG. Otherwise where the temp files are supposed to end up, not in system32 for sure.

I really appreciate and use try/catch whenever I run into trouble. String coded execscript is a perfect opportunity for trouble, especially syntax errors which are impossible to isolate.

cTempPath=""
cExecScript=""
function execScriptParam()
private lcReturn

if vartype(this.cTempPath)<>"C" or empty(this.cTempPath) or !directory(this.cTempPath)
    this.cTempPath=getenv("TEMP")
endif

cd (this.cTempPath)
this.cError=this.cError+"Temp folder: "+curdir()+"<br />"

if vartype(this.cExecScript)<>"C" or empty(this.cExecScript)
    this.cError=this.cError+"cExecScript is blank.<br />"
    return .f.
endif

this.cError=this.cError+"Trying to run cExecScript.<br />"
try
    lcReturn=execscript(this.cExecScript)
catch to oEx
    this.cError=this.cError+transform(oEx.ErrorNo)+": "+oEx.Message+" execscript<br />"
    this.lError=.t.
endtry
if vartype(lcReturn)=="C"
    **returns error message or whatever
    this.cError=this.cError+lcReturn+" in cExecScript<br />"
endif
if this.lError
    return .f.
endif
return .t.
endfunc && execScriptParam

3. I haven't finished working on the third part as it is optional. It automatically loads a file with the same name as the form but ".ef" extension containing additional tables and relations if those tables and relations weren't supplied by the original calling application.

The reason I need to do this is because my original application front end is still in use and I can't change it or block people from using it.

Because these files were made for a desktop front end, the .ef file also contains closing code to release the extra tables, but my application doesn't need that because everything I assume is released once PDFRUN halts.

Or do we need to close tables and release all?
Coordinator
Mar 31 at 10:02 PM
I just discovered that the problem may be the datasession being different in the oPDF object, but I would need to add some code to change the datasession and test it.

In some other objects I created I added set datasession to 1 in the init() function and it eliminated problems accessing tables.