Link to home
Start Free TrialLog in
Avatar of Mercer3
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.Destination.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','Refnum')" 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([xfrx062("XFRX#INIT")])
      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.collname)
            losession.settitle(sale_desc)
*       loSession.setSubject(thisform.text3.value)
*       loSession.setKeywords(thisform.text4.value)
            losession.setcreator(m.collname)
*       loSession.setProducer(thisform.text6.value)
*       loSession.setComments(thisform.text7.value)
*       loSession.setCategory(thisform.text8.value)
*       loSession.setManager(thisform.text9.value)
*          loSession.setCompany(m.lname)
            IF splashed = 'Y'
                  STORE "=selectdbf('Parameters')" TO COMMAND
                  &COMMAND
                  losession.processreport("splash")
            ENDIF
            SELECT sale2
            losession.processreport("LnSale1h")
            SELECT sale1
            losession.processreport("LnSale1")
            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


 

Avatar of CarlWarner
CarlWarner
Flag of United States of America image

<< 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. >>

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.
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.
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
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]
Avatar of Mercer3
Mercer3

ASKER

It is an application that creates many classes programatically of which several use the two mentioned Dlls
Avatar of Mercer3

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.
Avatar of Mercer3

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?
Avatar of Mercer3

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
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
<< 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?
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.
<< 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"
Avatar of Mercer3

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
ASKER CERTIFIED SOLUTION
Avatar of CarlWarner
CarlWarner
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mercer3

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.