我正在使用 Delphi XE7 开发 Windows 32 位应用程序。
我的应用程序包含许多单元,其中有一个初始化部分。我需要首先初始化一个特定的初始化部分。
可以设置优先级吗? 我尝试在 dpr 文件中写入初始化部分,但编译器拒绝了这一点。
请帮助我首先执行特定的初始化部分。预先感谢。
简单来说,初始化部分按照任何
uses
子句中引入单元的顺序执行。但它比这要复杂一点,因为单元的初始化仅在该单元本身引用的任何单元初始化之后执行(其中它们尚未初始化)。
即给定:
program Foo;
uses
Unit1,
Unit2,
Unit3;
unit Unit1;
interface
uses
Unit3;
那么单元初始化顺序将是:
Unit3
Unit1
Unit2
这是因为
Unit1
引入了 Unit3
,所以尽管 Unit1
在 dpr 使用中首先列出,但实际上 Unit3
首先被初始化,然后是 Unit1
的初始化。
如果您还记得
initialization
部分出现在单元中任何 uses
子句之后,那么它确实有意义。
因此,绝对确定任何一个单元在其他单元之前初始化的唯一方法是将其首先列在 DPR uses
子句中,并且该单元不依赖于任何其他单元(除非这些单元单元不依赖于或以其他方式干扰正在执行的初始化)。
当然不一定是“严格”首先。例如如果您使用替换内存管理器(例如 FastMM),那么这绝对需要成为 dpr
uses
子句中列出的第一个单元。您只需要确保您需要在任何其他(您的单元)之前初始化的单元然后在可能将您的其他单元引入的任何其他单元之前列出:
program Foo;
uses
FastMM, // MUST be first but won't bring any of 'my' units in, so this is OK
SysUtils, // These too are fine coming next because again they don't
Forms, // reference 'my' units
MyInitUnit, // <- This is where it is important to list 'my' guaranteed first/earliest
// initialisated unit of all 'my' units
MyFirstAppUnit, // And now the rest ...
etc;
当然,如果您希望首先初始化的单元确实
需要在任何
其他单元之前初始化,包括RTL单元(与FastMM等需要的方式相同),那么您需要在dpr uses
更早地声明您的单位来列出。
uses
因此,您可以通过在
uses
列表中向上移动您的设备来强制其首先初始化。
不幸的是,Delphi 文档具有误导性。根据我自己的研究,我发现单元并不总是按照它们在使用子句中引用的顺序进行初始化。如果您对我发现的内容不感兴趣,请跳过下一段。
初始化
部分 按照 DCU 写入磁盘的顺序调用,而不是按照 引用单位的顺序。对于简单的情况,两个 订单可以是等价的,但绝对不是真的 初始化代码总是按照单元的顺序调用 在单位条款中提及。如何强制执行初始化命令
当需要按特定顺序初始化单元时,我采用的方法是在每个需要初始化的单元中都有一个公共方法。该方法在initialization
部分调用。
对于每个单元,都有一个单元级(私有)变量,用于指示初始化是否已运行。 (对于简单的情况,布尔值就足够了,对于更复杂的情况,您可能会创建一个初始化对象,并且可以使用指向该对象的指针)。然后在每个模块中检查是否已初始化,如果没有,则调用之前需要初始化的所有其他单元中的初始化,然后进行自己的初始化。
因此,如果您使用简单的布尔值,您可能会:unit InitFirst;
interface
uses Classes;
procedure _DoInitialisation();
implementation
var
_blInitialised: Boolean;
procedure _DoInitialisation();
begin
if(not _blInitialised) then
begin
// initialisation code goes here
_blInitialised:=True;
end;
end;
initialization
_DoInitialisation();
end.
和
unit InitSecond;
interface
uses Classes;
procedure _DoInitialisation();
implementation
uses InitFirst;
var
_blInitialised: Boolean;
procedure _DoInitialisation();
begin
if(not _blInitialised) then
begin
InitFirst._DoInitialisation();
// initialisation code goes here
_blInitialised:=True;
end;
end;
initialization
_DoInitialisation();
end.