Understanding Exit Procedures
Exit procedures ensure that specific actionssuch as updating and closing filesare carried out before a program
terminates. The
ExitProc
pointer variable allows you to install an exit procedure, so that it is always called as part
of the program's terminationwhether the termination is normal, forced by a call to Halt, or the result of a runtime error.
An exit procedure takes no parameters.
Note:
It is recommended that you use finalization sections rather than exit procedures for all exit behavior.
Exit
procedures are available only for executables. For .DLLs (Win32) you can use a similar variable, DllProc,
which is called when the library is loaded as well as when it is unloaded. For packages, exit behavior must
be implemented in a finalization section. All exit procedures are called before execution of finalization
sections.
Units as well as programs can install exit procedures. A unit can install an exit procedure as part of its initialization
code, relying on the procedure to close files or perform other clean-up tasks.
When implemented properly, an exit procedure is part of a chain of exit procedures. The procedures are executed
in reverse order of installation, ensuring that the exit code of one unit isn't executed before the exit code of any units
that depend on it. To keep the chain intact, you must save the current contents of
ExitProc
before pointing it to
the address of your own exit procedure. Also, the first statement in your exit procedure must reinstall the saved value
of
ExitProc
.
223
The following code shows a skeleton implementation of an exit procedure.
var
ExitSave: Pointer;
procedure MyExit;
begin
ExitProc := ExitSave; // always restore old vector first
.
.
.
end;
begin
ExitSave := ExitProc;
ExitProc := @MyExit;
.
.
.
end.
On entry, the code saves the contents of
ExitProc
in
ExitSave
, then installs the
MyExit
procedure. When called
as part of the termination process, the first thing
MyExit
does is reinstall the previous exit procedure.
The termination routine in the runtime library keeps calling exit procedures until
ExitProc
becomes nilnil. To avoid
infinite loops,
ExitProc
is set to nil before every call, so the next exit procedure is called only if the current exit
procedure assigns an address to
ExitProc
. If an error occurs in an exit procedure, it is not called again.
An exit procedure can learn the cause of termination by examining the
ExitCode
integer variable and the
ErrorAddr
pointer variable. In case of normal termination,
ExitCode
is zero and
ErrorAddr
is nil. In case of
termination through a call to
Halt
,
ExitCode
contains the value passed to Halt and ErrorAddr is nil. In case of
termination due to a runtime error, ExitCode contains the error code and ErrorAddr contains the address of the invalid
statement.
The last exit procedure (the one installed by the runtime library) closes the Input and Output files. If ErrorAddr is not
nil, it outputs a runtime error message. To output your own runtime error message, install an exit procedure that
examines ErrorAddr and outputs a message if it's not nil; before returning, set ErrorAddr to nil so that the error is
not reported again by other exit procedures.
Once the runtime library has called all exit procedures, it returns to the operating system, passing the value stored
in ExitCode as a return code.
224
|