Delphi 初始化的顺序

时间:2023-03-10 04:24:18
Delphi 初始化的顺序

一、存储结构:

初始化单元存储在一个数组InitContext.InitTable^.UnitInfo中,其中UnitInfo是以数组的方式存储的,其中InitTable的定义为:

Delphi 初始化的顺序

其中InitTable定义为packageInfo的类型,再来看看PackageInfo的定义:

Delphi 初始化的顺序

可以看到PackageInfo中的UnitInfo被定义为PUnitEntryTable类型,接下来再看PUnitEntryTable的定义:

Delphi 初始化的顺序

可以看到单元例程存储在一个数组中,最大可以存储一千万个单元例程,每个例程函数中有Init和FInit两个入口函数,其中Init表示Initialization例程的入口地址,FInit为Finalization例程的入口地址;

结论:delphi初始化例程函数是以一个顺序列表的方式存储的;

 

二、初始化例程执行顺序:

初始化例程执行函数在System.pas单元的InitUnits函数中:

Delphi 初始化的顺序

结论:初始化执行是一个顺序循环执行过程,从0到Count – 1的顺序执行;

Finalization例程的执行是在System.pas单元的FinalizeUnits函数中:

Delphi 初始化的顺序

结论:Finalization执行是一个逆序循环执行过程,从Count - 1到0的逆序执行;

三、初始化例程搜索顺序:

单元例程的搜索顺序是编译器完成,无法看到代码,但是可以写一些小的Demo来猜测其搜索顺序;

如果在dpr中引用了Unit1,然后又在Unit1中引用了Unit2,接着在Unit2中引用了Unit3,那么在执行Initialization时先执行Unit3,再是Unit2,最后是Unit1;

如果在dpr中顺序引用Unit1, Unit2, Unit3,但是在Unit1中不引用Unit2,Unit2中不引用Unit3,那么在执行Initialization时先执行Unit1,再是Unit2,最后是Unit3;

结论:首先从dpr文件中加载第一个单元如A,在试图加载A的Initialization时,先查看A的uses部分,这里的uses不分Interface部分还是implementation部分,只分先后顺序,当发现A有Uses单元时,比如依次引用了单元B和C,则先将A压入堆栈,然后处理B,如果B引用了其他单元,处理方式同A,如果没有引用其他单元,则将B的例程保存到UnitEntryTable中(如果UnitEntryTable中已经有了B单元则不保存);接着以相同的方式处理C,当A引用的单元都处理完后将A从堆栈弹出并保存到UnitEntryTable中;其他单元依次处理;