代码之家  ›  专栏  ›  技术社区  ›  Heinrich Ulbricht

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

  •  12
  • Heinrich Ulbricht  · 技术社区  · 14 年前

    我正在寻找一个可能与单元初始化命令连接的bug。有没有办法看哪一个 initialization 节是什么时候执行的?我需要知道命令。这是在调试期间进行的,所以我拥有DelphiIDE的全部功能,在我的例子中是Delphi2009。

    我可以设置断点,但当有许多单元时,这相当繁琐。

    你有什么建议吗?

    5 回复  |  直到 12 年前
        1
  •  6
  •   splash    14 年前

    对于接口使用列表中的单元, 的初始化部分 客户端使用的单位在 单位显示的顺序 客户的use子句。

    看见 联机帮助\ Programs and Units \初始化部分 这篇文章: Understanding Delphi Unit initialization order

    ICARUS 计算 运行时初始化顺序 为了它 使用报表 :

    本节列出运行时执行初始化节的顺序。

        2
  •  9
  •   Jeroen Wiert Pluimers    12 年前

    这里是我在d2010中刚刚测试的一些代码,请注意,您需要在system.inituments中设置一个断点,并获取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;
    

    /编辑:下面是使用jclebug和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;
    

    在我的例子中,输出:

    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
    

    /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.
    

    我的系统上的输出(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
    
        3
  •  3
  •   Ritsaert Hornstra    14 年前

    您可以检查单元系统和SysInit,并查找initUnits过程。在这里,您可以看到用delphi编译的每个模块都有一个单元初始化和终结指针列表。使用这些加上一个映射文件可能会给你确切的初始化顺序,但它将采取一些指针黑客。

        4
  •  0
  •   David    14 年前

    加一点怎么样

    OutputDebugString('In MyUnit initialization'); 
    

    到初始化部分?

        5
  •  0
  •   Otherside    14 年前

    可以在所有不中断但将消息写入调试器日志的初始化节上设置断点。它将为您提供与添加相同的列表 OutputDebugString('...') 调用,但不必修改所有单元的源代码。