Understanding Delphi Unit initialization order

Posted: (EET/GMT+2)

 

Sometimes, Delphi developers get confused about the order in which their units get initialized and finalized. For instance, if you have code in an initialization section of a unit that depends on the initialization of another unit, chances are this coupling can break if you are not aware of the rules in which units are initialized and finalized.

If you take a look at the documentation that comes with Borland Delphi (or Borland Developer Studio), it just simply says that the order depends on the order which the units are listed in the project (.DPR) file. For simple cases, this is perfectly true, but it can get more difficult than that. Lets see a simple example with four units.

First, assume you have project file that looks like this:

program Project1;

uses
  Unit1 in 'Unit1.pas',
  Unit2 in 'Unit2.pas',
  Unit3 in 'Unit3.pas',
  Unit4 in 'Unit4.pas';

begin
  { some code here }
end.

Now, lets say all the units 1-4 look similar to this:

unit Unit1;

interface

implementation

uses Windows;

initialization
  OutputDebugString('Unit1 Initialization');
finalization
  OutputDebugString('Unit1 Finalization');
end.

In this simple situation, the units are initialized in order 1 to 4, and finalized in the opposite order, 4 to 1. This is easily proved by looking Delphi's Event Log debug window output:

Debug Output: Unit1 Initialization Process Project1.exe (1960)
Debug Output: Unit2 Initialization Process Project1.exe (1960)
Debug Output: Unit3 Initialization Process Project1.exe (1960)
Debug Output: Unit4 Initialization Process Project1.exe (1960)
...
Debug Output: Unit4 Finalization Process Project1.exe (1960)
Debug Output: Unit3 Finalization Process Project1.exe (1960)
Debug Output: Unit2 Finalization Process Project1.exe (1960)
Debug Output: Unit1 Finalization Process Project1.exe (1960)

Now, if you would change the order of the units in the Uses clause of the .DPR from "1-2-3-4" to say, "3-1-2-4", then the initialization order would be the same as the order in the Uses clause: 3-1-2-4. And, as you have learned, the finalization would happen in reverse order, giving 4-2-1-3. Easy, no?

Now, lets return to the basic order again (order 1-2-3-4). Since units often use other units, it is important to learn that this also affects the unit initialization order. So, what would happen if you would change Unit1 to use Unit4 in the interface section? Like this:

unit Unit1;

interface

uses Unit4;  <-- NOTE THIS

implementation

uses Windows;

initialization
  OutputDebugString('Unit1 Initialization');
finalization
  OutputDebugString('Unit1 Finalization');
end.

Now, what would the order look like in this case? Think of a chain. The initialization starts from the first unit in the .DPR Uses clause, so it goes to Unit1. But, if Unit1 uses any other unit (in this case, Unit4), that unit is initialized first. This is important to remember. So in this case, the output would be:

Debug Output: Unit4 Initialization Process Project1.exe (2680)
Debug Output: Unit1 Initialization Process Project1.exe (2680)
Debug Output: Unit2 Initialization Process Project1.exe (2680)
Debug Output: Unit3 Initialization Process Project1.exe (2680)
...
Debug Output: Unit3 Finalization Process Project1.exe (2680)
Debug Output: Unit2 Finalization Process Project1.exe (2680)
Debug Output: Unit1 Finalization Process Project1.exe (2680)
Debug Output: Unit4 Finalization Process Project1.exe (2680)

So suddenly, the order is 4-1-2-3! I hope this clarifies the situation.