unit UnmangleNameDemoMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, ComCtrls, StdCtrls, JclPeImage;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    OpenBtn: TButton;
    OpenDialog1: TOpenDialog;
    PeFileLabel: TLabel;
    PackageLabel: TLabel;
    FilenameLabel: TLabel;
    PackageDescrLabel: TLabel;
    PackageVerLabel: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure OpenBtnClick(Sender: TObject);
    procedure ListView1Data(Sender: TObject; Item: TListItem);
  private
    BorImage: TJclPeBorImage;
  public
    procedure UpdateInfo;
    class procedure LabelCaptionParam(Lbl: TLabel; const StringParam: string);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  ComObj, TypInfo,
  JclSysInfo, JclSysUtils, JclWin32;

// Demonstrates creating custom resource item classes

type
  TJclPeResourceStringItem = class (TJclPeResourceItem)
  public
    function GetItemIDString(const ItemID: Word): string;
  end;

  TJclDemoPeBorImage = class (TJclPeBorImage)
  protected
    function ResourceItemCreate(AEntry: PImageResourceDirectoryEntry;
      AParentItem: TJclPeResourceItem): TJclPeResourceItem; override;
  public
    function ResourceStringValue(const ID: Word): string;
  end;

{ TJclPeResourceStringItem }

function TJclPeResourceStringItem.GetItemIDString(const ItemID: Word): string;
var
  P: PWChar;
  Cnt: Cardinal;
  Len: Word;
begin
  Result := '';
  Assert(IsDirectory);
  P := List[0].RawEntryData;
  Cnt := 0;
  while Cnt < 16 do
  begin
    Len := Word(P^);
    if Len > 0 then
    begin
      Inc(P);
      if Cnt = ItemID then
      begin
        Result := PChar(WideCharLenToString(P, Len));
        Exit;
      end;
      Inc(P, Len);
    end else
      Inc(P);
    Inc(Cnt);
  end;
end;

{ TJclDemoPeBorImage }

function TJclDemoPeBorImage.ResourceItemCreate(AEntry: PImageResourceDirectoryEntry;
  AParentItem: TJclPeResourceItem): TJclPeResourceItem;
begin
  if (AParentItem <> nil) and (AParentItem.Level = 1) and (AParentItem.ResourceType = rtString) then
    Result := TJclPeResourceStringItem.Create(Self, AParentItem, AEntry)
  else
    Result := inherited ResourceItemCreate(AEntry, AParentItem);
end;

function TJclDemoPeBorImage.ResourceStringValue(const ID: Word): string;
var
  Item: TJclPeResourceItem;
  BlockID, ItemID: Word;
begin
  Result := '';
  BlockID := (ID div 16) + 1;
  ItemID := ID mod 16;
  Item := ResourceList.FindResource(rtString, IntToStr(BlockID));
  if Item <> nil then
    Result := (Item as TJclPeResourceStringItem).GetItemIDString(ItemID);
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  BorImage := TJclDemoPeBorImage.Create;
  OpenDialog1.InitialDir := GetWindowsSystemFolder;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(BorImage);
end;

procedure TForm1.OpenBtnClick(Sender: TObject);
begin
  with OpenDialog1 do
  begin
    FileName := '';
    if Execute then
    begin
      BorImage.FileName := FileName;
//      BorImage.ExportList.SortList(esOrdinal);
      UpdateInfo;
    end;
  end;
end;

procedure TForm1.UpdateInfo;
const
  YesNoText: array [Boolean] of string = ('[NO]', '[YES]');
begin
  ListView1.Items.Count := BorImage.ExportList.Count;
  ListView1.Invalidate;
  LabelCaptionParam(PeFileLabel, YesNoText[BorImage.IsBorlandImage]);
  LabelCaptionParam(PackageLabel, YesNoText[BorImage.IsPackage]);
  LabelCaptionParam(FilenameLabel, BorImage.FileName);
  if BorImage.IsPackage then
  begin
    LabelCaptionParam(PackageDescrLabel, BorImage.PackageInfo.Description);
    LabelCaptionParam(PackageVerLabel, IntToStr(BorImage.PackageCompilerVersion));
  end
  else
  begin
    LabelCaptionParam(PackageDescrLabel, '');
    LabelCaptionParam(PackageVerLabel, '');
  end;
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
var
  Unmangled, OriginalName, S, SectionName: string;
  Descr: TJclBorUmDescription;
  Res: TJclBorUmResult;
  TI: PTypeInfo;
  TD: PTypeData;
  ResString: PResStringRec;
begin
  with Item do
  begin
    OriginalName := BorImage.ExportList[Index].Name;
    Res := PeBorUnmangleName(OriginalName, Unmangled, Descr);
    if Res = urOk then
    begin
      Caption := Unmangled;
      S := Copy(GetEnumName(TypeInfo(TJclBorUmSymbolKind), Integer(Descr.Kind)), 3, 255);
      if smQualified in Descr.Modifiers then S := S + ' [Q]';
      if smLinkProc in Descr.Modifiers then S := S + ' [L]';
      SubItems.Add(S);
      case Descr.Kind of
        skRTTI:
          begin
            TI := BorImage.ExportList[Index].MappedAddress;
            SubItems.Add(Copy(GetEnumName(TypeInfo(TTypeKind), Integer(TI^.Kind)), 3, 255));
            SubItems.Add(TI^.Name);
            TD := GetTypeData(TI);
            case TI^.Kind of
              tkInterface:
                SubItems.Add(GUIDToString(TD^.Guid));
              tkMethod:
                SubItems.Add(GetEnumName(TypeInfo(TMethodKind), Integer(TD^.MethodKind)));
            end;
          end;
        skData:
          begin
            SectionName := BorImage.ExportList[Index].SectionName;
            SubItems.Add(SectionName);
            if (smQualified in Descr.Modifiers) and (SectionName = 'CODE') then
            begin // Exported data in CODE section are resourcestrings
              ResString := BorImage.ExportList[Index].MappedAddress;
              SubItems.Add(Format('ResString ID: %d', [ResString^.Identifier]));
              SubItems.Add(TJclDemoPeBorImage(BorImage).ResourceStringValue(ResString^.Identifier));
            end;
          end;
      end;
    end else
    begin // Not mangled or Microsoft compiler
      PeUnmangleName(OriginalName, Unmangled);
      Caption := Unmangled;
      SubItems.Add(GetEnumName(TypeInfo(TJclBorUmResult), Integer(Res)));
    end;
  end;
end;

class procedure TForm1.LabelCaptionParam(Lbl: TLabel; const StringParam: string);
var
  I: Integer;
begin
  with Lbl do
  begin
    I := Pos(':', Caption);
    if I = 0 then
      Caption := Caption + ': ' + StringParam
    else
      Caption := Copy(Caption, 1, I) + ' ' + StringParam;
  end;
end;

end.
