加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 使用运行时包编译的应用程序的单元最终确定顺序?

发布时间:2020-12-15 04:31:24 所属栏目:大数据 来源:网络整理
导读:我需要在完成SysUtils单元后执行我的代码. 我已将我的代码放在单独的单元中,并将其首先包含在dpr-file的uses子句中,如下所示: project Project1;uses MyUnit,// - my separate unit SysUtils,Classes,SomeOtherUnits;procedure Test;begin //end;begin SetP
我需要在完成SysUtils单元后执行我的代码.

我已将我的代码放在单独的单元中,并将其首先包含在dpr-file的uses子句中,如下所示:

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的finalization部分将在SysUtils的finalization部分之后执行.这是德尔福的帮助告诉我的.

然而,这并非总是如此.

我有2个测试应用程序,它们在使用中列出的Test例程/ dpr文件和单元中的代码略有不同.但是,MyUnit在所有情况下都列在第一位.

一个应用程序按预期运行:Halt0 – > FinalizeUnits – > ……其他单位… – > SysUtils的定稿 – > MyUnit的最终定稿 – > ……其他单位……

但第二个不是.在SysUtils完成之前调用MyUnit的终结.实际的调用链如下所示:Halt0 – > FinalizeUnits – > ……其他单位… – > SysUtils的定稿(跳过) – > MyUnit的最终定稿 – > ……其他单位… – > SysUtils的定稿(执行)

两个项目都有非常相似的设置.我尝试了很多来消除/减少他们的差异,但我仍然没有看到这种行为的原因.

我试图调试这个并发现:似乎每个单元都有某种引用计数.似乎InitTable包含对同一单元的多次引用.当第一次调用SysUtils的终结部分时 – 它会更改引用计数器而不执行任何操作.然后执行MyUnit的终结.然后再次调用SysUtils,但这次ref-count达到零并执行终结部分:

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
...

任何人都可以轻视这个问题吗?我错过了什么吗?

解决方法

单位按初始化的相反顺序最终确定.初始化顺序由非循环(即从不下降到已访问单元)确定单元使用图的后序遍历,从主要使用子句(在程序或库中)开始. SysInit通常是第一个要初始化的单元,其次是System.

动态加载包会使事情变得复杂,因为主EXE或DLL可以指定主图像使用的单元的初始化顺序.因此,当一个包被动态加载时,它将运行它认为应该是初始化顺序的包,但是已经初始化的单元将被跳过;当动态卸载程序包时,会发生相反的情况.

一般规则:

>在较高级别的事情之前,应该初始化较低级别的事物
> finalization应该与初始化的顺序相反

这些规则几乎总是有意义的.较高级别单位的初始化通常依赖于较低级别单位提供的服务.例如,没有SysUtils,Delphi中没有异常支持.反向顺序最终确定也是有道理的:高级终结依赖于较低级别单元提供的服务,因此它们必须在较低级别单元的最终确定之前运行.

所有这一切,关于你的问题,听起来在编译器或RTL中可能存在某个错误,如果你说的是真的:主EXE首先使用MyUnit,而MyUnit在其接口中不使用其他单元或实现,动态加载的包没有搞笑的业务.我所能建议的是用奇怪的行为继续削减项目,直到你有一个最小的再现样本;在那一点上,应该清楚究竟是什么导致了这个问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读