help

53 views
Skip to first unread message

aurora baccio

unread,
Jun 13, 2021, 2:38:49 AMJun 13
to
Good morning and good Sunday
I cannot close an archive (ProvPres.dbf) .
For other archives I use :
oInError := InError{,false}
.......
oInError:Close()

end of the procedure

oIrror := InError{,false}
oInError:Zap()
oInError:Close()

The Archive that I can't close feeds a subdatawindow contained in a datadialog and all the data that the user has to check arrives. If everything is correct it proceeds and then :
oProvPres{}:Close()
.........
.ProvPres := oProvPres{,false}
oProvPres:Zap()
oProvPres:Close()

self:Destroy()
I restart the activity assuming that the ProvPres.dbf archive has been reset.
I notice that this procedure does not work, the archive remains open with the data of the previous operation.
I ask for help.
Thanks
Aurora Baccio

Wolfgang Riedmann

unread,
Jun 15, 2021, 12:54:27 AMJun 15
to
Buon giorno Aurora,

AFAIK you need to open a DBF in exclusive mode do execute the Zap()
method.
I suspect that there is another instance open that does not permit to
execute thzap operation.

You should make sure that the SubDataWindow is closed and cleaned up.
More than using a :Destroy() call on it I would null it out and issue a
CollectForced() call.

Wolfgang
--

aurora baccio

unread,
Jun 15, 2021, 3:06:18 PMJun 15
to
Good evening Mr. Riedman and welcome back.
I am reasonably sure that the sub date is closed.
At the end of the procedure I close with oProvPres:Close() the archive in question.
After several attempts I inserted a close databases
I didn't understand why, since all the archives had to be closed but since then the archive zap works.
To be sure of what I do:
oProvPres := ProvPres{,false}
oProvPres:Zap()
oProvPres:Close()
from here on starts the whole procedure of building the recipe delivery.
When the recipe is registered and archived

I close the datadialog
self:Destroy()

I close the archive.

oProvPres:Close()
close databases
CollectForced()

From what I understand you suggest not to use destroy().
How do I use collectForced ?
Exactly I read that collectforced() skips the garbage collection but honestly I still don't understand why it didn't work before and now it does.
I know one of the rules of computer science is to never ask why, but I remain curious.
thanks
Aurora Baccio


Translated with www.DeepL.com/Translator (free version)

JohnMartens

unread,
Jun 15, 2021, 4:03:24 PMJun 15
to
Hi Aurora,

Several comments on your issue.

Zap only works if the DBF is only used in exclusive mode that should be
set bij SetExclusive(TRUE). It should not be open in other parts of your
app. I think the DBF was open in parts of your app that you are not
aware of and therefore you cannot zap it.

You can use this code to see what DBF's are open

cMsg := ''
FOR wAlias := 1 UPTO 1024
cAlias := ALIAS(wAlias)
IF .NOT. ( cAlias == NULL_STRING )
dwMethresult += 1
cMsg += NTrim(wAlias)+' workarea<.>'
cMsg += '<9>Alias<9><9>'+cAlias+'<.>'
cMsg += '<9>File name<9><9>'+ (cAlias)->(DBINFO(DBI_FULLPATH))+'<.>'
cMsg += '<9>Locked records<9>'+
NTrim((cAlias)->(DBINFO(DBI_LOCKCOUNT)))+'<.>'
ENDIF
NEXT

Put the code in a funtion that you call when debugging your app to see
what DBF's are open en check wether these are the ones that you expect
to be open.
I'm sure that somewhere you did not close a DBF and thyerefore you
cannot ZAP it

I'm having a DBF where lots of changes take place. To prvent the DBF
growing by adding records and deleting them without being able to ZAP
it. I'm using special delete and apend methods of the DBF

METHOD DeleteToReuse() CLASS MySpecialDbf
lResult := SUPER:Delete()
IF lResult
SELF:Filed1 := ""
SELF:Field2 := ""
ENDIF
RETURN lResult

When appending

METHOD AppendReuse() CLASS MySpecialDbf
LOCAL lMethResult AS LOGIC
LOCAL lDeleted AS LOGIC
LOCAL dwRecNr := 0 AS DWORD

lDeleted := SetDeleted()
SetDeleted(FALSE)

DO CASE
CASE ! SELF:Seek(Space(10)) // Seek on first empty field that can
only be empty when deleted
CASE ! SELF:Recall()
* Message that deleted record cannot be recalled
OTHERWISE
dwRecNr := SELF:RecNo
lMethResult := TRUE
ENDCASE

SetDeleted(lDeleted)

IF dwRecNr = 0
* no old record found that could be recalled
lMethResult := SUPER:Append()
ELSE
* empty record recalled
SELF:GoTo(dwRecNr)
ENDIF
RETURN lMethResult

In this way your DBF will not be for ever growing and there is no need
to have a EXCLUSIVE access to the DBF

CollectForced() is normaly not needed unless you do not clean all memory
by ending resources.

When debugging I put this in my shellwindow
METHOD Timer() CLASS MyShellWindow
SELF:StatusBar:SetText(NTrim(Memory(MEMORY_REGISTERAXIT)),#MemoryAxit)
RETURN NIL
If the memory keeps on growing then you hev and issue with nog ending
windows of window parameters neatly.
I you close it down in the right way there is no need to use Destroy()

Hope this can help you

Cheers,
John


Op 15-6-2021 om 21:06 schreef aurora baccio:

Wolfgang Riedmann

unread,
Jun 16, 2021, 3:08:32 AMJun 16
to
Buon giorno Aurora,

the Destroy() method only cleans up ressources used by the window.
Therefore the DBF used by the subdatawindow may not be closed when the
Destroy() method of the owning DataDialog is called.

CollectForced() triggers a call of the garbage collector, and this call
cleans up all unused ressources, regardless where in the program they
were used.

The garbage collector in the VO runtime is a complicated but very
important piece of software, and for some more advanced tasks it is
important to understand how it works. I also had examples where a
CollectForced() call leaded to GPFs in the program, but that was always
the programmers ( = my ) fault.

Wolfgang
--

Reply all
Reply to author
Forward
0 new messages