更改Delphi中单元的初始化顺序

问题描述 投票:0回答:3

我正在使用 Delphi XE7 开发 Windows 32 位应用程序。

我的应用程序包含许多单元,其中有一个初始化部分。我需要首先初始化一个特定的初始化部分。

可以设置优先级吗? 我尝试在 dpr 文件中写入初始化部分,但编译器拒绝了这一点。

请帮助我首先执行特定的初始化部分。预先感谢。

delphi delphi-xe7
3个回答
16
投票

简单来说,初始化部分按照任何

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

0
投票

因此,您可以通过在

uses
列表中向上移动您的设备来强制其首先初始化。

不幸的是,Delphi 文档具有误导性。根据我自己的研究,我发现单元并不总是按照它们在使用子句中引用的顺序进行初始化。如果您对我发现的内容不感兴趣,请跳过下一段。


0
投票
使用 SysInternals 的实用程序 ProcMon 并监控进程 构建 Delphi 代码时我可以看到单元文件何时打开,以及何时打开 DCU 文件已写入。似乎单元文件是在 在uses子句中引用它们的顺序,但是编译后的 DCU 可以按不同的顺序写入。通过将断点放入 我已经确认它们是单位的

初始化

部分 按照 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.

© www.soinside.com 2019 - 2024. All rights reserved.