Unit finalization order for application, compiled with run-time packages?
- by Alexander
I need to execute my code after finalization of SysUtils unit.
I've placed my code in separate unit and included it first in uses clause of dpr-file, like this:
project Project1;
uses
MyUnit, // <- my separate unit
SysUtils,
Classes,
SomeOtherUnits;
procedure Test;
begin
//
end;
begin
SetProc(Test);
end.
MyUnit looks like this:
unit MyUnit;
interface
procedure SetProc(AProc: TProcedure);
implementation
var
Test: TProcedure;
procedure SetProc(AProc: TProcedure);
begin
Test := AProc;
end;
initialization
finalization
Test;
end.
Note that MyUnit doesn't have any uses.
This is usual Windows exe, no console, without forms and compiled with default run-time packages. MyUnit is not part of any package (but I've tried to use it from package too).
I expect that finalization section of MyUnit will be executed after finalization section of SysUtils. This is what Delphi's help tells me.
However, this is not always the case.
I have 2 test apps, which differs a bit by code in Test routine/dpr-file and units, listed in uses. MyUnit, however, is listed first in all cases.
One application is run as expected: Halt0 - FinalizeUnits - ...other units... - SysUtils's finalization - MyUnit's finalization - ...other units...
But the second is not. MyUnit's finalization is invoked before SysUtils's finalization. The actual call chain looks like this: Halt0 - FinalizeUnits - ...other units... - SysUtils's finalization (skipped) - MyUnit's finalization - ...other units... - SysUtils's finalization (executed)
Both projects have very similar settings. I tried a lot to remove/minimize their differences, but I still do not see a reason for this behaviour.
I've tried to debug this and found out that: it seems that every unit have some kind of reference counting. And it seems that InitTable contains multiply references to the same unit. When SysUtils's finalization section is called first time - it change reference counter and do nothing. Then MyUnit's finalization is executed. And then SysUtils is called again, but this time ref-count reaches zero and finalization section is executed:
Finalization: // SysUtils' finalization
5003B3F0 55 push ebp // here and below is some form of stub
5003B3F1 8BEC mov ebp,esp
5003B3F3 33C0 xor eax,eax
5003B3F5 55 push ebp
5003B3F6 688EB50350 push $5003b58e
5003B3FB 64FF30 push dword ptr fs:[eax]
5003B3FE 648920 mov fs:[eax],esp
5003B401 FF05DCAD1150 inc dword ptr [$5011addc] // here: some sort of reference counter
5003B407 0F8573010000 jnz $5003b580 // <- this jump skips execution of finalization for first call
5003B40D B8CC4D0350 mov eax,$50034dcc // here and below is actual SysUtils' finalization section
...
Can anyone can shred light on this issue? Am I missing something?