Can I determine the order in which my units have been initialized? Can I determine the order in which my units have been initialized? windows windows

Can I determine the order in which my units have been initialized?


Here is some code I just tested in D2010, note that you need to set a Breakpoint in System.InitUnits and get the address of InitContext var (@InitContext). Then modify CtxPtr to have this address WHILE STILL RUNNING. (Maybe someone knows a smarter way for this).

procedure TForm3.Button2Click(Sender: TObject);var  sl: TStringList;  ps: PShortString;  CtxPtr: PInitContext;begin  // Get the address by setting a BP in SysUtils.InitUnits (or map file?)  CtxPtr := PInitContext($4C3AE8);  sl := TStringList.Create;  try    ps := CtxPtr^.Module^.TypeInfo^.UnitNames;    for i := 0 to CtxPtr^.Module^.TypeInfo^.UnitCount - 1 do    begin      sl.Add(ps^);      // Move to next unit      DWORD(ps) := DWORD(ps) + Length(ps^) + 1;    end;    Memo1.Lines.Assign(sl);  finally    sl.Free;  end;end;

/EDIT: and here is a version using JclDebug and a mapfile:

type  TForm3 = class(TForm)  ...  private    { Private declarations }    var      Segments: array of DWORD;    procedure PublicsByValue(Sender: TObject; const Address: TJclMapAddress; const Name: string);    procedure MapSegment(Sender: TObject; const Address: TJclMapAddress; Len: Integer; const GroupName, UnitName: string);    procedure MapClassTable(Sender: TObject; const Address: TJclMapAddress; Len: Integer; const SectionName, GroupName: string);  public    { Public declarations }  end;var  Form3: TForm3;  CtxPtr: PInitContext = nil; // Global varprocedure TForm3.MapClassTable(Sender: TObject; const Address: TJclMapAddress;  Len: Integer; const SectionName, GroupName: string);begin  SetLength(Segments, Length(Segments) + 1);  SegMents[Address.Segment-1] := Address.Offset;end;procedure TForm3.PublicsByValue(Sender: TObject; const Address: TJclMapAddress;  const Name: string);const  InitContextStr = 'System.InitContext';begin  if RightStr(Name, Length(InitContextStr)) = InitContextStr then  begin    CtxPtr := PInitContext(Segments[Address.Segment-1] + Address.Offset);  end;end;procedure TForm3.Button2Click(Sender: TObject);var  MapParser: TJclMapParser;  MapFile: String;  sl: TStringList;  ps: PShortString;  i: Integer;begin  MapFile := ChangeFileExt(Application.ExeName, '.map');  MapParser := TJclMapParser.Create(MapFile);  try    MapParser.OnPublicsByValue := PublicsByValue;    MapParser.OnClassTable := MapClassTable;    MapParser.Parse;  finally    MapParser.Free;  end;  if CtxPtr = nil then    Exit;  sl := TStringList.Create;  try    ps := CtxPtr^.Module^.TypeInfo^.UnitNames;    for i := 0 to CtxPtr^.Module^.TypeInfo^.UnitCount - 1 do    begin      sl.Add(ps^);      // Move to next unit      DWORD(ps) := DWORD(ps) + Length(ps^) + 1;    end;    Memo1.Lines.Assign(sl);  finally    sl.Free;  end;end;

Output in my case:

VariantsVarUtilsWindowsTypesSysInitSystemSysConstSysUtilsCharacterRTLConstsMathStrUtilsImageHlpMainUnitJwaWinNetWkJwaWinTypeJwaWinNTJwaWinDLLNamesJwaWinErrorStdCtrlsDwmapiUxThemeSyncObjsClassesActiveXMessagesTypInfoTimeSpanCommCtrlThemesControlsFormsStdActnsComCtrlsCommDlgShlObjStructuredQueryConditionPropSysObjectArrayUrlMonWinInetRegStrShellAPIComStrsConstsPrintersGraphicsRegistryIniFilesIOUtilsMasksDateUtilsWincodecWinSpoolActnListMenusImgListContnrsGraphUtilZLibListActnsExtCtrlsDialogsHelpIntfsMultiMonDlgsWideStrUtilsToolWinRichEditClipbrdFlatSBImmTpcShrd

/EDIT2: And here a version for D2009 (requires JclDebug):

unit MainUnit;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StrUtils, JclDebug, StdCtrls;type  TForm1 = class(TForm)    Button1: TButton;    Memo1: TMemo;    procedure Button1Click(Sender: TObject);  private    { Private declarations }    var      Segments: array of DWORD;    procedure PublicsByValue(Sender: TObject; const Address: TJclMapAddress; const Name: string);    procedure MapClassTable(Sender: TObject; const Address: TJclMapAddress; Len: Integer; const SectionName, GroupName: string);  public    { Public declarations }  end;var  Form1: TForm1;  CtxPtr: PInitContext = nil; // Global var  Symbols: TStringList;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);var  MapParser: TJclMapParser;  MapFile: String;  sl: TStringList;  ps: PShortString;  i: Integer;  s: String;  Idx: Integer;begin  MapFile := ChangeFileExt(Application.ExeName, '.map');  MapParser := TJclMapParser.Create(MapFile);  try    MapParser.OnPublicsByValue := PublicsByValue;    MapParser.OnClassTable := MapClassTable;    Memo1.Lines.BeginUpdate;    MapParser.Parse;    Memo1.Lines.EndUpdate;  finally    MapParser.Free;  end;  if CtxPtr = nil then    Exit;  sl := TStringList.Create;  try    for i := 0 to CtxPtr^.InitTable.UnitCount-1 do    begin      if Assigned(CtxPtr^.InitTable.UnitInfo^[i].Init) then      begin        s := Format('$%.8x', [DWORD(CtxPtr^.InitTable.UnitInfo^[i].Init)]);        Idx := Symbols.IndexOfObject(TObject(CtxPtr^.InitTable.UnitInfo^[i].Init));        if Idx > -1 then        begin          Memo1.Lines.Add(Format('%.4d: %s', [i, Symbols[Idx]]));        end;      end;    end;  finally    sl.Free;  end;end;procedure TForm1.MapClassTable(Sender: TObject; const Address: TJclMapAddress;  Len: Integer; const SectionName, GroupName: string);begin  SetLength(Segments, Length(Segments) + 1);  SegMents[Address.Segment-1] := Address.Offset;end;procedure TForm1.PublicsByValue(Sender: TObject; const Address: TJclMapAddress;  const Name: string);const  InitContextStr = 'System.InitContext';begin  if RightStr(Name, Length(InitContextStr)) = InitContextStr then  begin    CtxPtr := PInitContext(Segments[Address.Segment-1] + Address.Offset);  end  else begin    Symbols.AddObject(Name, TObject(Segments[Address.Segment-1] + Address.Offset));  end;end;initialization  Symbols := TStringList.Create;  Symbols.Sorted := True;  Symbols.Duplicates := dupIgnore;finalization  FreeAndNil(Symbols);end.

Output on my system (Unitname.Unitname is actually Unitname.Initialization):

0001: System.System0003: Windows.Windows0011: SysUtils.SysUtils0012: VarUtils.VarUtils0013: Variants.Variants0014: TypInfo.TypInfo0016: Classes.Classes0017: IniFiles.IniFiles0018: Registry.Registry0020: Graphics.Graphics0023: SyncObjs.SyncObjs0024: UxTheme.UxTheme0025: MultiMon.MultiMon0027: ActnList.ActnList0028: DwmApi.DwmApi0029: Controls.Controls0030: Themes.Themes0032: Menus.Menus0033: HelpIntfs.HelpIntfs0034: FlatSB.FlatSB0036: Printers.Printers0047: GraphUtil.GraphUtil0048: ExtCtrls.ExtCtrls0051: ComCtrls.ComCtrls0054: Dialogs.Dialogs0055: Clipbrd.Clipbrd0057: Forms.Forms0058: JclResources.JclResources0059: JclBase.JclBase0061: JclWin32.JclWin320063: ComObj.ComObj0064: AnsiStrings.AnsiStrings0065: JclLogic.JclLogic0066: JclStringConversions.JclStringConversions0067: JclCharsets.JclCharsets0068: Jcl8087.Jcl80870073: JclIniFiles.JclIniFiles0074: JclSysInfo.JclSysInfo0075: JclUnicode.JclUnicode0076: JclWideStrings.JclWideStrings0077: JclRegistry.JclRegistry0078: JclSynch.JclSynch0079: JclMath.JclMath0080: JclStreams.JclStreams0081: JclAnsiStrings.JclAnsiStrings0082: JclStrings.JclStrings0083: JclShell.JclShell0084: JclSecurity.JclSecurity0085: JclDateTime.JclDateTime0086: JclFileUtils.JclFileUtils0087: JclConsole.JclConsole0088: JclSysUtils.JclSysUtils0089: JclUnitVersioning.JclUnitVersioning0090: JclPeImage.JclPeImage0091: JclTD32.JclTD320092: JclHookExcept.JclHookExcept0093: JclDebug.JclDebug0094: MainUnit.MainUnit


For units in the interface uses list, the initialization sections of the units used by a client are executed in the order in which the units appear in the client's uses clause.

see Online Help \ Programs and Units \ The Initialization Section and this article: Understanding Delphi Unit initialization order

ICARUS computes the Runtime initialization order for its Uses Report:

This section lists the order in which the initialization sections are executed at runtime.


You might check out the unit System and SysInit and look for the procedure InitUnits. Here you see that every module compiled with Delphi has a list of units initialization and finalization pointers. Using those plus a map file might give you the exact initialization order, but it will take some pointer hackery.