我可以确定我的单位初始化的顺序吗?

Hei*_*cht 13 windows delphi debugging desktop-application delphi-2009

我正在寻找可能与单元初始化顺序相关的错误.有没有办法看到哪个initialization部分执行时?我需要知道订单.这是在调试期间,所以我拥有Delphi IDE的全部功能,在我的案例中是Delphi 2009.

我可以设置断点,但是当有很多单位时这是相当繁琐的.

你有什么建议吗?

Rem*_*mko 10

以下是我刚刚在D2010中测试的一些代码,请注意您需要在System.InitUnits中设置一个断点并获取InitContext var(@InitContext)的地址.然后修改CtxPtr以使此地址仍然运行.(也许有人知道更明智的方式).

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;
Run Code Online (Sandbox Code Playgroud)

/编辑:这是一个使用JclDebug和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 var

procedure 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;
Run Code Online (Sandbox Code Playgroud)

在我的情况下输出:

Variants
VarUtils
Windows
Types
SysInit
System
SysConst
SysUtils
Character
RTLConsts
Math
StrUtils
ImageHlp
MainUnit
JwaWinNetWk
JwaWinType
JwaWinNT
JwaWinDLLNames
JwaWinError
StdCtrls
Dwmapi
UxTheme
SyncObjs
Classes
ActiveX
Messages
TypInfo
TimeSpan
CommCtrl
Themes
Controls
Forms
StdActns
ComCtrls
CommDlg
ShlObj
StructuredQueryCondition
PropSys
ObjectArray
UrlMon
WinInet
RegStr
ShellAPI
ComStrs
Consts
Printers
Graphics
Registry
IniFiles
IOUtils
Masks
DateUtils
Wincodec
WinSpool
ActnList
Menus
ImgList
Contnrs
GraphUtil
ZLib
ListActns
ExtCtrls
Dialogs
HelpIntfs
MultiMon
Dlgs
WideStrUtils
ToolWin
RichEdit
Clipbrd
FlatSB
Imm
TpcShrd
Run Code Online (Sandbox Code Playgroud)

/ EDIT2:这里是D2009的一个版本(需要JclDebug):

unit MainUnit;

interface

uses
  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.
Run Code Online (Sandbox Code Playgroud)

我的系统上的输出(Unitname.Unitname实际上是Unitname.Initialization):

0001: System.System
0003: Windows.Windows
0011: SysUtils.SysUtils
0012: VarUtils.VarUtils
0013: Variants.Variants
0014: TypInfo.TypInfo
0016: Classes.Classes
0017: IniFiles.IniFiles
0018: Registry.Registry
0020: Graphics.Graphics
0023: SyncObjs.SyncObjs
0024: UxTheme.UxTheme
0025: MultiMon.MultiMon
0027: ActnList.ActnList
0028: DwmApi.DwmApi
0029: Controls.Controls
0030: Themes.Themes
0032: Menus.Menus
0033: HelpIntfs.HelpIntfs
0034: FlatSB.FlatSB
0036: Printers.Printers
0047: GraphUtil.GraphUtil
0048: ExtCtrls.ExtCtrls
0051: ComCtrls.ComCtrls
0054: Dialogs.Dialogs
0055: Clipbrd.Clipbrd
0057: Forms.Forms
0058: JclResources.JclResources
0059: JclBase.JclBase
0061: JclWin32.JclWin32
0063: ComObj.ComObj
0064: AnsiStrings.AnsiStrings
0065: JclLogic.JclLogic
0066: JclStringConversions.JclStringConversions
0067: JclCharsets.JclCharsets
0068: Jcl8087.Jcl8087
0073: JclIniFiles.JclIniFiles
0074: JclSysInfo.JclSysInfo
0075: JclUnicode.JclUnicode
0076: JclWideStrings.JclWideStrings
0077: JclRegistry.JclRegistry
0078: JclSynch.JclSynch
0079: JclMath.JclMath
0080: JclStreams.JclStreams
0081: JclAnsiStrings.JclAnsiStrings
0082: JclStrings.JclStrings
0083: JclShell.JclShell
0084: JclSecurity.JclSecurity
0085: JclDateTime.JclDateTime
0086: JclFileUtils.JclFileUtils
0087: JclConsole.JclConsole
0088: JclSysUtils.JclSysUtils
0089: JclUnitVersioning.JclUnitVersioning
0090: JclPeImage.JclPeImage
0091: JclTD32.JclTD32
0092: JclHookExcept.JclHookExcept
0093: JclDebug.JclDebug
0094: MainUnit.MainUnit
Run Code Online (Sandbox Code Playgroud)


spl*_*ash 7

对于接口使用列表中的单元,客户端使用的单元的初始化部分按照单元出现在客户端的uses子句中的顺序执行.

请参阅联机帮助\ 程序和单位 \初始化部分和本文:了解Delphi单元初始化顺序

ICARUS为其使用报告计算运行时初始化顺序:

本节列出了在运行时执行初始化部分的顺序.