单元确定订单的应用程序,使用运行时包编译? [英] Unit finalization order for application, compiled with run-time packages?
问题描述
我将代码放在单独的单元中,并将其首先包含在dpr文件的uses子句中,如下所示:
project Project1;
使用
MyUnit,//< - 我的单独单元
SysUtils,
类,
SomeOtherUnits;
程序测试;
begin
//
end;
begin
SetProc(Test);
结束。
MyUnit如下所示:
unit MyUnit;
界面
程序SetProc(AProc:TProcedure);
实现
var
测试:TProcedure;
程序SetProc(AProc:TProcedure);
begin
测试:= AProc;
结束
初始化
finalization
测试;
结束。
请注意,MyUnit没有任何用处。
这是通常的Windows exe,没有控制台,没有表单,并使用默认的运行时包进行编译。 MyUnit不是任何包的一部分(但我也试图从包中使用它)。
我希望MyUnit的定稿部分将被执行SysUtils的完成部分。这是Delphi的帮助告诉我的。
但是,并不总是这样。
我有2测试应用程序,在使用中列出的Test routine / dpr文件和单元中的代码有所不同。然而,MyUnit在所有情况下都是首先列出的。
一个应用程序按预期运行: Halt0 - > FinalizeUnits - > ...其他单元... - > SysUtils的完成 - > MyUnit的完成 - >。 ..其他单位...
但第二个不是。 MyUnit的最终确定在 SysUtils的最终确定之前被调用。实际的电话链如下所示: Halt0 - > FinalizeUnits - > ...其他单位... - > SysUtils的最终确定(跳过) - > MyUnit的最终确定 - > ...其他单位... - > SysUtils的最终确定(执行)
两个项目都有非常相似的设置。我尝试删除/最小化他们的差异,但我仍然没有看到这个行为的原因。
我试图调试这个,发现:看来每个单位都有某种参考计数。而且,似乎InitTable包含对相同单元的乘法引用。当SysUtils的最终确定部分被称为第一次 - 它会改变引用计数器,什么都不做。然后执行MyUnit的完成。然后SysUtils再次被调用,但这次ref-count达到零并执行完成部分:
Finalization:// SysUtils 'finalization
5003B3F0 55 push ebp //这里和下面是一些形式的存根
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] //这里:某种参考计数器
5003B407 0F8573010000 jnz $ 5003b580 //< - 此跳过跳过执行第一次调用的完成
5003B40D B8CC4D0350 mov eax,$ 50034dcc //这里和下面是实际的SysUtils'最终确定部分
...
任何人都可以在这个问题上闪光?我错过了什么吗?
我找到了一个理由,现在觉得自己有点傻了:)
我的第二个测试应用程序具有静态引用到DLL,它是用RTL.bpl编译的(它是空的,除了引用SysUtils并有1个简单例程)。所以,由于DLL是静态链接的,所以在exe有任何代码有机会运行之前被初始化。
就是这样:
DLL的系统 - > DLL的 SysUtils - > exe的系统(跳过) - > MyUnit exe的 SysUtils (跳过) - > etc
结束语是相反的顺序,导致在SysUtils之前执行MyUnit。
解决方案:需要在所有项目中首先包含MyUnit。
(哦,我希望有一台时间机器回来及时强制有人添加OnBeforeMMShutdown事件:D)
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?
I was able to find a reason and I feel myself a bit stupid now :)
My second test application have a static reference to DLL, which was compiled with RTL.bpl (it's empty, except for references to SysUtils and having 1 simple routine). So, since DLL is statically linked, it is initialized before any code from exe have chances to run.
That's it:
DLL's System -> DLL's SysUtils -> exe's System (skipped) -> MyUnit -> exe's SysUtils (skipped) -> etc
Finalizations are in reverse order, leading to execution of MyUnit before SysUtils.
Solution: require to include MyUnit first in all projects.
(oh, how I wish to have a time-machine to travel back in time and force somebody to add OnBeforeMMShutdown event :D )
这篇关于单元确定订单的应用程序,使用运行时包编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!