Ordem de finalização da unidade para o aplicativo, compilada com pacotes de tempo de execução?
Preciso executar meu código após a finalização da unidade SysUtils.
Coloquei meu código em uma unidade separada e o incluí primeiro na cláusula uses do dpr-file, assim:
project Project1;
uses
MyUnit, // <- my separate unit
SysUtils,
Classes,
SomeOtherUnits;
procedure Test;
begin
//
end;
begin
SetProc(Test);
end.
MyUnit é assim:
unit MyUnit;
interface
procedure SetProc(AProc: TProcedure);
implementation
var
Test: TProcedure;
procedure SetProc(AProc: TProcedure);
begin
Test := AProc;
end;
initialization
finalization
Test;
end.
Observe que MyUnit não tem nenhum uso.
Esse é o exe comum do Windows, sem console, sem formulários e compilado com pacotes de tempo de execução padrão. MyUnit não faz parte de nenhum pacote (mas eu tentei usá-lo também).
Espero que a seção de finalização do MyUnit seja executada após a seção de finalização do SysUtils. Isto é o que a ajuda de Delphi me diz.
No entanto, esse nem sempre é o caso.
Eu tenho 2 aplicativos de teste, que diferem um pouco do código na rotina de teste / arquivo dpr e unidades, listadas nos usos. MyUnit, no entanto, é listado primeiro em todos os casos.
Um aplicativo é executado conforme o esperado:Halt0 -> FinalizeUnits -> ... outras unidades ... -> finalização do SysUtils -> finalização do MyUnit -> ... outras unidades ...
Mas o segundo não é. A finalização do MyUnit é invocadaantes Finalização do SysUtils. A cadeia de chamadas real é assim:Halt0 -> FinalizeUnits -> ... outras unidades ... -> Finalização do SysUtils (ignorada) -> Finalização do MyUnit -> ... outras unidades ... -> Finalização do SysUtils (executada)
Ambos os projetos têm configurações muito semelhantes. Tentei muito remover / minimizar as diferenças, mas ainda não vejo uma razão para esse comportamento.
Eu tentei depurar isso e descobri o seguinte: parece que cada unidade tem algum tipo de contagem de referência. E parece que InitTable contém referências multiplicadas para a mesma unidade. Quando a seção de finalização do SysUtils é chamada pela primeira vez - ele altera o contador de referência e não faz nada. A finalização do MyUnit é executada. E então o SysUtils é chamado novamente, mas desta vez ref-count chega a zero e a seção de finalização é executada:
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
...
Alguém pode esclarecer essa questão? Estou esquecendo de algo?