Getting rid of the 322/5333 error with Clipper & Fivewin
Here I’ll explain how I got rid of the dreaded 322 and
5333 Clipper errors with FiveWin apps. What I’ll present here is product of
comments and fragments of codes of different FiveWin users, as well as mine.
This doesn’t pretend to be a
technical explanation as of why it happens, nor if the use of Memory(-1) is good
or evil. This is what’s worked for me for over a year an a half (with some new
things thrown in along the way) with the final result of no more reports from
users (or in my own PC) of the 322 or 5333 Clipper errors. Tested both, Clipper
5.2e and 5.3e, plus FiveWin 2.1c, I’m sure it applies just as well to any
version of FiveWin 2.0 or higher.
To see why the calls to
Memory(-1), make sure you app has a message bar object and double click on it to
see FiveWin reporting the memory usage (FW 2.1 and above). You’ll see that the
value returned by MemUsed() goes down much more when Memory(-1) is used. Also
notice how high MemMax() gets. My experienced showed me that when it reached
16,000,000 the app just died; using Memory(-1) as shown below helped keep
MemMax() at bay. Please feel free to comment out the use of Memory(-1) to see
the difference by yourself.
Credits here go to Peter Kohler,
Alex Isamat and myself. If I omit someone, please let me know and forgive my
forgetfulness.
Also, some users haven’t seemed
to ever experience these errors, while others have with different impact. So if
you haven’t run across this error, I would suggest no to touch anything: if
it ain’t broke, don’t fix it.
Disclaimer: If this doesn’t work
for you or if you PC starts a fires, I cannot be held liable. This is free
advice and code sharing with no responsibility on my part.
Luis Krause
November 11, 2002
1.- Adjust your link script
file like this:
BLINKER INCREMENTAL OFF
BLINKER EXECUTABLE COMPRESS 1 # use ONLY with Blinker 5.x and above
BLINKER CLIPPER SYMBOL ON
File
YourMainPrg
File
MoreSourceCode
#
Blinker 5.0 and above file to replace module in Clipper.Lib
File
MPar
# The
following files ONLY if you use Clipper 5.2e
#
These were extracted from Clipper.Lib from Clipper 5.3b
# You
must own Clipper 5.3b; I won’t provide you with these modules
File
Alloc, OM, Memory
Lib
OtherLIbsYouMightBeUsing
PACKCODE
PACKDATA
DEFBEGIN
name AppName
description 'The Best Thing Around Town'
exetype Windows 3.1
code preload moveable discardable
data preload moveable
rc YourResFile.res //
instead of external
YourResFile.dll - mutually exclusive!
stacksize 16500 // this figure depends on your app
heapsize 5120 // this figure depends on your app
segment 'PLANKTON_TEXT' nondiscardable
segment 'EXTEND_TEXT' nondiscardable
//segment 'OM_TEXT' nondiscardable // because of OM.OBJ call above
segment 'OSMEM_TEXT' nondiscardable
segment 'SORTOF_TEXT' nondiscardable
segment 'STACK_TEXT' nondiscardable
DEFEND
Library Five, FiveC, Objects, WinApi
Library Clipper, Extend, Terminal
2.- Adjust your
YourMainPrg.prg file:
#include “FiveWin.ch”
Static
oWnd, oGarbage
Function Main()
Define
Window oWnd ;
Title “Test App” ;
Menu BuildMenu() ;
MDI
Define
Message Bar Of oWnd Keyboard Date Clock
//
more of you stuff
Activate Window oWnd ;
On
Init InitApp()
Return
Nil
//---------------------------------------------
Static
Function BuildMenu()
Local
oMenu
//
here goes you menu
Return
oMenu
//---------------------------------------------
Static
Function InitApp()
SetHandleCount( 180 ) // or whatever suits you
//
Define and start the Timer that controls the Garbage Collector
oGarbage := TTimer():New( 60000, ;
{||
SysRefresh(), ;
If( MemMax() > 15000000 .and. MemUsed() > 15000000, ;
( oGarbage:DeActivate(), ;
MsgAlert( "Memory resources running low" + CRLF + ;
"Please restart the program ASAP", “Your App” ), ;
oGarbage:Activate() ), ;
( Memory(-1), Memory(-1), Memory(-1), Memory(-1), Memory(-1) ) ) },
oWnd )
Eval(
oGarbage:bAction ) // start our own "garbage collector"
oGarbage:Activate()
Return
Nil
//---------------------------------------------
Exit
Function EndApp()
If
oGarbage # Nil
oGarbage:end()
Endif
Return
Nil
//---------------------------------------------
3.- Modify TDialog Class,
::Initate() method:
METHOD
Initiate( hWndFocus, hWnd ) CLASS Tdialog
//
current code
#ifdef __CLIPPER__
Memory(-1) // Add this line
ASend( ::aControls, "Initiate", ::hWnd )
#else
ASend( ::aControls, "Initiate()", ::hWnd )
#endif
//
current code
Return
lFocus // .t. for default focus
4.- Modify TMDIChild Class,
::End() method (code has been optimized from original):
METHOD
End() CLASS TMdiChild
Local lEnd := ::lValid()
If
lEnd
if ::oMenu != nil .and. ! ::lKeepMenu
::oMenu:End()
endif
::oWndClient:ChildClose( Self )
SetIdleAction( {|| KillMemHog() } ) // free memory hogged by FW's MDI'S
Endif
Return
lEnd
// add this new static function at the end of mdichild.prg
//----------------------------------------------------------------------------//
//
Helper function adapted from Peter Kohler's idea
Static
Function KillMemHog()
/*
clean up memory after MDI windows close.
This
seems to work quite well to force Clipper to clean up memory after
you
close a MDI dialog/Window: You can't call
memory(-1) directly at the end of your MDI window as the window is still
open
using the memory you want to release,
so
you have to call it somehow a few seconds after your MDI window closes.
Must
be a function, not a method, which would keep the object in memory.
*/
Static
nSeconds := 0
Local
nCount := 0
If
nSeconds == 0
nSeconds := Seconds()
Endif
If
Seconds() - nSeconds > 2
//
Clear idle action
SetIdleAction()
nSeconds := 0
For
nCount := 1 To 16 // feel free to adjust this to suit your needs
Memory(-1)
Next
Endif
Return
Nil
So
that’s it. Make those changes to both, your code and the mentioned FiveWin
classes and you should see the dreaded 322 & 5333 errors go away, just like I
did.