3

I had an issue where a file kept deleting on startup and I couldn't track down the code responsible. I wound up adding Vcl.Dialogs to all the units and creating an initialization section that looked like this:

initialization
begin
  ShowMessage('Inside [Unit Name Here]');
end;

This was quite a pain. Is there an easy way to generate a list of forms/units in the order in which they fire off?

UPDATE: 2019-08-01 (Helpful MAP links)

Here are two links that may assist in understanding DELPHI map files

  1. http://docwiki.embarcadero.com/RADStudio/Rio/en/API_%28%2A.map%29

  2. Understanding Delphi MAP File

  • https://stackoverflow.com/a/52103952/62576 – Ken White Jul 29 '19 at 02:51
  • See also [Tools to generate unit dependencies for Delphi](https://stackoverflow.com/q/3076048/576719) – LU RD Jul 29 '19 at 05:24
  • Possible duplicate: https://stackoverflow.com/questions/4076425/can-i-determine-the-order-in-which-my-units-have-been-initialized/4077426#4077426 – Remko Jul 29 '19 at 10:50

2 Answers2

8

You really didn't need to go to all that trouble modifying your source units. I think you'll find that using the method below will find the misbehaving unit much more quickly than somehow generating a list of units and then ploughing your way through it.

If you look in System.Pas, you'll find a procedure InitUnits like this (from D7).

procedure InitUnits;
var
  Count, I: Integer;
  Table: PUnitEntryTable;
  P: Pointer;
begin
  if InitContext.InitTable = nil then
    exit;
  Count := InitContext.InitTable^.UnitCount;
  I := 0;
  Table := InitContext.InitTable^.UnitInfo;
  [...]
  try
    while I < Count do
    begin
      P := Table^[I].Init;
      Inc(I);
      InitContext.InitCount := I;
      if Assigned(P) then
      begin
        TProc(P)();
      end;
    end;
  except
    FinalizeUnits;
    raise;
  end;
end;

This is the code which causes the initialization code of each unit to be called. It works its way through the units and calls the initialization section (if any) of each unit via the call

  TProc(P)();

You can inspect the value of Count prior to the loop; don't be surprised if its upwards of a couple of hundreds even for a relatively simple project.

Put a breakpoint on the TProc(P)(); line and right-click and set the PassCount to half the value of Count. Run your app and when the breakpoint trips, check whether the file has been deleted.

You can then do a binary search through the values of Count (by continuing the current run if the file is still there, or resetting the app and halving the Pass Count) to establish exactly which unit causes the file to be deleted. Because you can use a binary search to do this, it will rapidly converge on the unit which is deleting the file. Of course, you can trace into the unit's initialization code (if it has been compiled with debug info) when the breakpoint trips by pressing F7 on TProc(P)();

MartynA
  • 30,454
  • 4
  • 32
  • 73
7

You can inspect the segments section of the map file. The entries with C=ICODE are those units with initialization parts in the order they are executed.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130