Mercer3
asked on
Class/application not being removed from memory
I have some code that generates a pdf using xfrx by calling specific report applications from within a FoxPro Executable. The issue that I am having is that I can not get the application/classes/dlls to unload inbetween calls to the various report applications. One of the properties that are contained within the classes that prints pdf's from xfrx is the (report name frx), because the application is not unloaded all of the associated classes are still in memory even though I have released the object that has referred to the class and I can not print another type of report unless I exit from the main executable.
This were I call the initial report
Store "DO " + Template_Path + TEMPLATE + " With " + ALLTRIM(STR(THISForm.Pages .Options.D estination .Value)) + ", '" + ; Pview + "'" + ", '" + Splash + "'" + ", '" + RptSummary + "'" + ", '" + Filter1 + "'" + ", '" + Filter2 + "'" + ", '" + Filter3 + "'" ; + ", '" + Filter4 + "'" + ", '" + Filter5 + "'" to RUNREPORT
&RUNREPORT
The report application is called properly
PARAMETERS displayhow, prevrpt, splash, rptsummary, parm1, parm2, parm3, parm4, parm5
PUBLIC sale_id, sale_desc, userinput
STORE splash TO splashed
STORE .F. TO m.userinput
STORE 'Sale Accounts as of:' + DTOC(DATE()) TO sale_desc
STORE "=opendbf(file_path + 'Data\Parameters','entry') " TO COMMAND
&COMMAND
STORE "=selectdbf('Parameters')" TO COMMAND
&COMMAND
SEEK 'Splash'
STORE "=OPENDBF(FILE_PATH + 'Data\Sale_ID','Sale_ID')" TO COMMAND
&COMMAND
STORE "=OPENDBF(FILE_PATH + 'Data\Accounts','Acct_No') " TO COMMAND
&COMMAND
STORE "=OPENDBF(FILE_PATH + 'Data\Transactions','Refnu m')" TO COMMAND
&COMMAND
STORE "=SelectDBF('Accounts')" TO COMMAND
&COMMAND
DO FORM USER
IF m.userinput = .F.
MESSAGEBOX('Report cancelled by User', 16, M.product + ' - LoanSale-001')
RETURN
ENDIF
STORE "=SelectDBF('Accounts')" TO COMMAND
&COMMAND
SELECT accounts.acct_no, accounts.d1first, accounts.d1last,;
accounts.d1town, accounts.d1state, accounts.d1ssn, accounts.dateloss,;
accounts.statute,accounts. d1adress, accounts.d1wkphone,;
accounts.d1hmphone, accounts.d2first, accounts.d2middle, accounts.d2last,;
accounts.d2adress, accounts.d2town, accounts.d2state, accounts.d2ssn,;
accounts.prin_bal, accounts.interest AS acct_int, accounts.d2wkphone,;
accounts.d2hmphone, accounts.intcalced, accounts.intrate,;
accounts.previous;
FROM accounts ;
WHERE accounts.sale_id = M.sale_id;
ORDER BY accounts.d1state, accounts.acct_no;
INTO CURSOR sale2
SELECT accounts.acct_no, accounts.d1first, accounts.d1last,;
accounts.d1town, accounts.d1state, accounts.d1ssn, accounts.dateloss,;
accounts.statute, TRANSACTIONS.DATE, TRANSACTIONS.TRANSACT,;
TRANSACTIONS.refnum, TRANSACTIONS.PAYMENT, TRANSACTIONS.interest,;
TRANSACTIONS.balance, accounts.d1adress, accounts.d1wkphone,;
accounts.d1hmphone, accounts.d2first, accounts.d2middle, accounts.d2last,;
accounts.d2adress, accounts.d2town, accounts.d2state, accounts.d2ssn,;
accounts.prin_bal, accounts.interest AS acct_int, accounts.d2wkphone,;
accounts.d2hmphone, accounts.intcalced, accounts.intrate,;
accounts.previous;
FROM accounts inner JOIN TRANSACTIONS ;
ON accounts.acct_no = TRANSACTIONS.refnum;
WHERE accounts.sale_id = M.sale_id;
ORDER BY accounts.d1state, accounts.acct_no;
INTO CURSOR sale1
SET DEFAULT TO &template_path
IF INLIST(displayhow,1,3)
***** Splash Screen - printing determination is made in stdrpts options
IF splash = 'Y'
STORE "REPORT FORM splash.frx NOEJECT NOCONSOLE TO PRINTER" TO runreport
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
ENDIF
***** Header Record - No Summary Option
SELECT sale2
STORE "REPORT FORM LnSale1h NOEJECT NOCONSOLE TO PRINTER" TO runreport
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
***** Detail Records - Summary Option
SELECT sale1
IF rptsummary = 'Y'
STORE "REPORT FORM LnSale1 NOEJECT NOCONSOLE SUMMARY TO PRINTER" TO runreport
ELSE
STORE "REPORT FORM LnSale1 NOEJECT NOCONSOLE TO PRINTER" TO runreport
ENDIF
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
ENDIF
IF INLIST(displayhow,1,2)
STORE '' TO losession
STORE '' TO lnretval
STORE ALLTRIM(sale_desc) + '.PDF' TO pdfname
IF FILE(report_path + ALLTRIM(pdfname))
ERASE report_path + pdfname
ENDIF
losession=EVALUATE([xfrx06 2("XFRX#IN IT")])
IF prevrpt = 'Y'
lnretval = losession.setparams(report _path+ pdfname,,,,,,"PDF")
ELSE
lnretval = losession.setparams(report _path+ pdfname,,.T.,,,,"PDF")
ENDIF
IF lnretval = 0
losession.setauthor(m.coll name)
losession.settitle(sale_de sc)
* loSession.setSubject(thisf orm.text3. value)
* loSession.setKeywords(this form.text4 .value)
losession.setcreator(m.col lname)
* loSession.setProducer(this form.text6 .value)
* loSession.setComments(this form.text7 .value)
* loSession.setCategory(this form.text8 .value)
* loSession.setManager(thisf orm.text9. value)
* loSession.setCompany(m.lna me)
IF splashed = 'Y'
STORE "=selectdbf('Parameters')" TO COMMAND
&COMMAND
losession.processreport("s plash")
ENDIF
SELECT sale2
losession.processreport("L nSale1h")
SELECT sale1
losession.processreport("L nSale1")
losession.finalize
losession = .NULL.
lnretval = .NULL.
ENDIF
ENDIF
SET DEFAULT TO &file_path
SET FILTER TO
RETURN
The report creates the pdf and everything is A-OK, after the report is closed, I execute the following commands;
CLEAR PROGRAM
CLEAR DLLS "hndlib","zlib"
CLEAR CLASS "xfrx062"
The next time through I call a different report and it throws a error stating that it cannot find the report form LnSale1h.frx. The report that I am generating does not have this report form (LnSale1h) it usee a different report and the actual report name is completely different. It appears that the report form in the first call is stuck in memory land.
I have proved this by recompiling the first report application and I get an access is denied error message when it goes to write the Application executable to the same location where it ran prior. Of course this happens only if I do not close out of the calling execuatble that called the application in question with the do statement above. If I close the program that dynamically requests the report it frees up and I can replace the application but this is not the issue only one of the symptoms.
The question is how do I clear or unload an application called by FoxPro executable without having to shut down the main FoxPro Executable, clearing all references to classes and dlls that were called within the DLL. I do not have the source code to know what is going on within the xfrx.app which calls the hlib.dll and zlib.dll to produce the pdfs from the report data. I have used Clear Program, DLL, Class in the main executable as well as return in the called application.
I am doing this in FoxPro 8.0 if it matters.......
Mercer
This were I call the initial report
Store "DO " + Template_Path + TEMPLATE + " With " + ALLTRIM(STR(THISForm.Pages
&RUNREPORT
The report application is called properly
PARAMETERS displayhow, prevrpt, splash, rptsummary, parm1, parm2, parm3, parm4, parm5
PUBLIC sale_id, sale_desc, userinput
STORE splash TO splashed
STORE .F. TO m.userinput
STORE 'Sale Accounts as of:' + DTOC(DATE()) TO sale_desc
STORE "=opendbf(file_path + 'Data\Parameters','entry')
&COMMAND
STORE "=selectdbf('Parameters')"
&COMMAND
SEEK 'Splash'
STORE "=OPENDBF(FILE_PATH + 'Data\Sale_ID','Sale_ID')"
&COMMAND
STORE "=OPENDBF(FILE_PATH + 'Data\Accounts','Acct_No')
&COMMAND
STORE "=OPENDBF(FILE_PATH + 'Data\Transactions','Refnu
&COMMAND
STORE "=SelectDBF('Accounts')" TO COMMAND
&COMMAND
DO FORM USER
IF m.userinput = .F.
MESSAGEBOX('Report cancelled by User', 16, M.product + ' - LoanSale-001')
RETURN
ENDIF
STORE "=SelectDBF('Accounts')" TO COMMAND
&COMMAND
SELECT accounts.acct_no, accounts.d1first, accounts.d1last,;
accounts.d1town, accounts.d1state, accounts.d1ssn, accounts.dateloss,;
accounts.statute,accounts.
accounts.d1hmphone, accounts.d2first, accounts.d2middle, accounts.d2last,;
accounts.d2adress, accounts.d2town, accounts.d2state, accounts.d2ssn,;
accounts.prin_bal, accounts.interest AS acct_int, accounts.d2wkphone,;
accounts.d2hmphone, accounts.intcalced, accounts.intrate,;
accounts.previous;
FROM accounts ;
WHERE accounts.sale_id = M.sale_id;
ORDER BY accounts.d1state, accounts.acct_no;
INTO CURSOR sale2
SELECT accounts.acct_no, accounts.d1first, accounts.d1last,;
accounts.d1town, accounts.d1state, accounts.d1ssn, accounts.dateloss,;
accounts.statute, TRANSACTIONS.DATE, TRANSACTIONS.TRANSACT,;
TRANSACTIONS.refnum, TRANSACTIONS.PAYMENT, TRANSACTIONS.interest,;
TRANSACTIONS.balance, accounts.d1adress, accounts.d1wkphone,;
accounts.d1hmphone, accounts.d2first, accounts.d2middle, accounts.d2last,;
accounts.d2adress, accounts.d2town, accounts.d2state, accounts.d2ssn,;
accounts.prin_bal, accounts.interest AS acct_int, accounts.d2wkphone,;
accounts.d2hmphone, accounts.intcalced, accounts.intrate,;
accounts.previous;
FROM accounts inner JOIN TRANSACTIONS ;
ON accounts.acct_no = TRANSACTIONS.refnum;
WHERE accounts.sale_id = M.sale_id;
ORDER BY accounts.d1state, accounts.acct_no;
INTO CURSOR sale1
SET DEFAULT TO &template_path
IF INLIST(displayhow,1,3)
***** Splash Screen - printing determination is made in stdrpts options
IF splash = 'Y'
STORE "REPORT FORM splash.frx NOEJECT NOCONSOLE TO PRINTER" TO runreport
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
ENDIF
***** Header Record - No Summary Option
SELECT sale2
STORE "REPORT FORM LnSale1h NOEJECT NOCONSOLE TO PRINTER" TO runreport
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
***** Detail Records - Summary Option
SELECT sale1
IF rptsummary = 'Y'
STORE "REPORT FORM LnSale1 NOEJECT NOCONSOLE SUMMARY TO PRINTER" TO runreport
ELSE
STORE "REPORT FORM LnSale1 NOEJECT NOCONSOLE TO PRINTER" TO runreport
ENDIF
IF prevrpt = 'Y'
STORE ALLTRIM(runreport) + " PREVIEW" TO runreport
ELSE
STORE ALLTRIM(runreport) + " PROMPT" TO runreport
ENDIF
&runreport
ENDIF
IF INLIST(displayhow,1,2)
STORE '' TO losession
STORE '' TO lnretval
STORE ALLTRIM(sale_desc) + '.PDF' TO pdfname
IF FILE(report_path + ALLTRIM(pdfname))
ERASE report_path + pdfname
ENDIF
losession=EVALUATE([xfrx06
IF prevrpt = 'Y'
lnretval = losession.setparams(report
ELSE
lnretval = losession.setparams(report
ENDIF
IF lnretval = 0
losession.setauthor(m.coll
losession.settitle(sale_de
* loSession.setSubject(thisf
* loSession.setKeywords(this
losession.setcreator(m.col
* loSession.setProducer(this
* loSession.setComments(this
* loSession.setCategory(this
* loSession.setManager(thisf
* loSession.setCompany(m.lna
IF splashed = 'Y'
STORE "=selectdbf('Parameters')"
&COMMAND
losession.processreport("s
ENDIF
SELECT sale2
losession.processreport("L
SELECT sale1
losession.processreport("L
losession.finalize
losession = .NULL.
lnretval = .NULL.
ENDIF
ENDIF
SET DEFAULT TO &file_path
SET FILTER TO
RETURN
The report creates the pdf and everything is A-OK, after the report is closed, I execute the following commands;
CLEAR PROGRAM
CLEAR DLLS "hndlib","zlib"
CLEAR CLASS "xfrx062"
The next time through I call a different report and it throws a error stating that it cannot find the report form LnSale1h.frx. The report that I am generating does not have this report form (LnSale1h) it usee a different report and the actual report name is completely different. It appears that the report form in the first call is stuck in memory land.
I have proved this by recompiling the first report application and I get an access is denied error message when it goes to write the Application executable to the same location where it ran prior. Of course this happens only if I do not close out of the calling execuatble that called the application in question with the do statement above. If I close the program that dynamically requests the report it frees up and I can replace the application but this is not the issue only one of the symptoms.
The question is how do I clear or unload an application called by FoxPro executable without having to shut down the main FoxPro Executable, clearing all references to classes and dlls that were called within the DLL. I do not have the source code to know what is going on within the xfrx.app which calls the hlib.dll and zlib.dll to produce the pdfs from the report data. I have used Clear Program, DLL, Class in the main executable as well as return in the called application.
I am doing this in FoxPro 8.0 if it matters.......
Mercer
You may want to just try the SYS(1104) function to see whether it helps.
Without getting to the root cause, it's a guessing game. Capturing the environment either to a file or interactively in a Debug session may provide the clues to the culprit.
Without getting to the root cause, it's a guessing game. Capturing the environment either to a file or interactively in a Debug session may provide the clues to the culprit.
One weird observation, can you see whether leaving off the quotes in the CLEAR CLASS line makes a difference? Subtle things can cause unintended problems.
CLEAR CLASS "xfrx062"
to
CLEAR CLASS xfrx062
CLEAR CLASS "xfrx062"
to
CLEAR CLASS xfrx062
One last thought before I go offline...
Is "xfrx062" a Class or a ClassLib?
If it is possibly a ClassLib instead of a Class, use the following syntax instead:
RELEASE CLASSLIB ClassLibraryName1 | ALIAS AliasName1
[, ClassLibraryName2 | ALIAS AliasName2 …]
[IN APPFileName | EXEFileName]
Is "xfrx062" a Class or a ClassLib?
If it is possibly a ClassLib instead of a Class, use the following syntax instead:
RELEASE CLASSLIB ClassLibraryName1 | ALIAS AliasName1
[, ClassLibraryName2 | ALIAS AliasName2 …]
[IN APPFileName | EXEFileName]
ASKER
It is an application that creates many classes programatically of which several use the two mentioned Dlls
ASKER
I compile that application into the report application so I guess it is a classlib of some sorts
Yeah, after looking at your reference to the Class, I thought it may actually be a bigger picture collection of classes and in fact a ClassLib instead. Hence the last reference to RELEASE CLASSLIB.
ASKER
Nada, I can not release the classlib because the class definitions are in the application, I am still getting the access is denied and the report conflict. Question, I am still getting a DLL staying in memory even though I clered it and it is only used in this application. I used clear dll......why?
ASKER
Additionally, if I wait several minutes, after executing all of the commands the issue regarding the acess denied clears up. It is almost like it has to wait for garbage collection. Is there any way to force garbage collection to see if that will eliminate the problem?
I don't really know what will fit in your case.
Maybe info here will help:
ManualGarbageCollection
http://fox.wikis.com/wc.dll?Wiki~ManualGarbageCollection~VFP
Maybe info here will help:
ManualGarbageCollection
http://fox.wikis.com/wc.dll?Wiki~ManualGarbageCollection~VFP
I just now found this reference. And while I don't know if it will help you, it should be good stuff by Rick Hodder, the author.
Garbage Collection in Visual FoxPro
http://gethelp.devx.com/techtips/vfox_pro/10min/10min0800/10min0800.asp
Garbage Collection in Visual FoxPro
http://gethelp.devx.com/techtips/vfox_pro/10min/10min0800/10min0800.asp
<< if I wait several minutes, after executing all of the commands the issue regarding the acess denied clears up. >>
And your statement applies then to the DLL that was staying in memory even after the CLEAR DLL command, right?
Is that DLL developed by the xFrx folks or is it something else available out there to help the process?
And your statement applies then to the DLL that was staying in memory even after the CLEAR DLL command, right?
Is that DLL developed by the xFrx folks or is it something else available out there to help the process?
I did a little sleuthing on the DLLs.
It looks like HNDLIB.DLL is the developer of xFrx's own DLL.
ZLIB.DLL is a freeware compression utility by Zlib at http://www.zlib.org .
Which one is hanging on too long?
If it's the one developed by xFrx, they may know of the problem and already have a permanent solution and explanation.
It looks like HNDLIB.DLL is the developer of xFrx's own DLL.
ZLIB.DLL is a freeware compression utility by Zlib at http://www.zlib.org .
Which one is hanging on too long?
If it's the one developed by xFrx, they may know of the problem and already have a permanent solution and explanation.
<< CLEAR DLLS "hndlib","zlib" >>
Another thing to try would be to separate the operation of clearing the DLLs to two CLEAR DLLS commands listing only one at a time and reversing the order of CLEARing if the first attempt doesn't work. Stranger things have worked out like that.
CLEAR DLLS "hndlib"
CLEAR DLLS "zlib"
or
CLEAR DLLS "zlib"
CLEAR DLLS "hndlib"
Another thing to try would be to separate the operation of clearing the DLLs to two CLEAR DLLS commands listing only one at a time and reversing the order of CLEARing if the first attempt doesn't work. Stranger things have worked out like that.
CLEAR DLLS "hndlib"
CLEAR DLLS "zlib"
or
CLEAR DLLS "zlib"
CLEAR DLLS "hndlib"
ASKER
Carl,
I will be trying all of your suggestions and most likely will award you the points. I finally have the time to review all of the alternatives to resolve my error.
Mercer
I will be trying all of your suggestions and most likely will award you the points. I finally have the time to review all of the alternatives to resolve my error.
Mercer
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I am still working through your solution(s), I will most likely award them (the points) to you soon. I tried to implement the new version of the third party software to no avail.
OK. If I can help somehow (?), let me know.
Can you put in some temporary code (or go ahead and interactively debug) what is left in your environment to know what you may be missing? DISPLAY MEMORY will of course show the variable references while DISPLAY STATUS could show some library or other reference that you may not be aware of.