Трябва да изпълня кода си след финализиране на модула SysUtils.
Поставих кода си в отделна единица и го включих първо в клаузата uses на dpr-файл, като този:
project Project1;
uses
MyUnit, // <- my separate unit
SysUtils,
Classes,
SomeOtherUnits;
procedure Test;
begin
//
end;
begin
SetProc(Test);
end.
MyUnit изглежда така:
unit MyUnit;
interface
procedure SetProc(AProc: TProcedure);
implementation
var
Test: TProcedure;
procedure SetProc(AProc: TProcedure);
begin
Test := AProc;
end;
initialization
finalization
Test;
end.
Имайте предвид, че MyUnit няма никакви приложения.
Това е обикновен Windows exe, без конзола, без формуляри и компилиран с пакети за изпълнение по подразбиране. MyUnit не е част от нито един пакет (но се опитах да го използвам и от пакет).
Очаквам, че секцията за финализиране на MyUnit ще бъде изпълнена след секцията за финализиране на SysUtils. Това ми казва помощта на Delphi.
Това обаче не винаги е така.
Имам 2 тестови приложения, които се различават малко по кода в Тестова рутина/dpr-файл и единици, изброени в употреби. MyUnit обаче е посочен първи във всички случаи.
Едно приложение се изпълнява според очакванията: Halt0 -> FinalizeUnits -> ...други модули... -> Финализиране на SysUtils -> Финализиране на MyUnit -> ...други модули...
Но второто не е така. Финализирането на MyUnit се извиква преди финализирането на SysUtils. Действителната верига на повикванията изглежда така: Halt0 -> FinalizeUnits -> ...други модули... -> Финализиране на SysUtils (пропуснато) -> Финализиране на MyUnit -> ...други модули... -> Финализиране на SysUtils (изпълнено)
И двата проекта имат много сходни настройки. Опитах много да премахна/минимизирам различията им, но все още не виждам причина за това поведение.
Опитах се да отстраня грешки в това и открих, че: изглежда, че всяка единица има някакъв вид преброяване на референтни данни. И изглежда, че InitTable съдържа множество препратки към една и съща единица. Когато разделът за финализиране на SysUtils бъде извикан за първи път - той променя брояча на референтните данни и не прави нищо. След това се изпълнява финализирането на MyUnit. След това SysUtils се извиква отново, но този път броят на реф достига нула и секцията за финализиране се изпълнява:
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
...
Може ли някой да хвърли светлина по този въпрос? Изпускам ли нещо?