
unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, Pirate_PE, Tabs, StdCtrls, ExtCtrls, Menus, ComCtrls;

type
  TNodeData = Cardinal;
  PNodeData = ^TNodeData;

  TViewType = (vtHex, vtText, vtBMP, vtICO);

  TForm1 = class(TForm)
    MainMenu: TMainMenu;
    File1: TMenuItem;
    Open1: TMenuItem;
    N1: TMenuItem;
    Exit1: TMenuItem;
    mmSaveRes: TMenuItem;
    pc: TPageControl;
    tsHdr: TTabSheet;
    HdrList: TListView;
    MDSList: TListView;
    tsSec: TTabSheet;
    SecList: TListView;
    tsDir: TTabSheet;
    DirList: TListView;
    tsExp: TTabSheet;
    ExportList: TListView;
    tsImp: TTabSheet;
    ImportBox: TListBox;
    FuncBox: TListBox;
    tsRes: TTabSheet;
    ResPanel: TPanel;
    tsUnits: TTabSheet;
    UnitBox: TListBox;
    tsForms: TTabSheet;
    FormBox: TListBox;
    pDFM: TPanel;
    DFM: TMemo;
    tsPkgs: TTabSheet;
    PkgBox: TListBox;
    tsClasses: TTabSheet;
    ClassBox: TListBox;
    tsFlags: TTabSheet;
    FlagBox: TListBox;
    tsVersion: TTabSheet;
    VerList: TListView;
    ClientPanel: TPanel;
    ImagePanel: TPanel;
    Image: TImage;
    tsHeader: TTabSet;
    tsNETMD: TTabSheet;
    tsDebug: TTabSheet;
    DebugList: TListView;
    tsLoadConfig: TTabSheet;
    LCList: TListView;
    MDTree: TTreeView;
    Panel3: TPanel;
    ResTree: TTreeView;
    ResPropList: TListView;
    MemoPanel: TPanel;
    Memo: TMemo;
    tsExc: TTabSheet;
    ExcList: TListView;
    tsTLS: TTabSheet;
    TLSList: TListView;
    HexPanel: TPanel;
    HexBox: TListBox;
    HeaderControl1: THeaderControl;
    sbSec: TStatusBar;
    sbDir: TStatusBar;
    sbExp: TStatusBar;
    sbImp: TStatusBar;
    sbDebug: TStatusBar;
    sbExc: TStatusBar;
    sbUnit: TStatusBar;
    sbDFM: TStatusBar;
    sbPkg: TStatusBar;
    sbClass: TStatusBar;
    CVList: TListView;
    PopupMenu1: TPopupMenu;
    pmViewas: TMenuItem;
    Hex1: TMenuItem;
    ext1: TMenuItem;
    Bitmap1: TMenuItem;
    Icon1: TMenuItem;
    Saveresource2: TMenuItem;
    N4: TMenuItem;
    ObjectBox: TListBox;
    od: TOpenDialog;
    sd: TSaveDialog;
    procedure acOpenAccept(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ImportBoxClick(Sender: TObject);
    procedure acSaveResAccept(Sender: TObject);
    procedure FormBoxClick(Sender: TObject);
    procedure tsHeaderChange(Sender: TObject; NewTab: Integer;
      var AllowChange: Boolean);
    procedure DebugListSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure cmViewResAs(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ResTreeChange(Sender: TObject; Node: TTreeNode);
    procedure ResTreeDeletion(Sender: TObject; Node: TTreeNode);
    procedure Exit1Click(Sender: TObject);
  private
    PE: TPirate_PE;
    FFN: string;
    procedure HexListBox(ABox: TListBox; AData: Pointer; ASize: Cardinal);
    procedure LoadResourceToView(ResItem: TResourceItem);
    procedure ResetControls;
    procedure ClearControls;
    procedure ViewResourceAs(AView: TViewType; ResItem: TResourceItem);
  public
    procedure OpenFile(AFilename: string);
    procedure SaveResource(ResItem: TResourceItem; AFilename: string);
    procedure DisplayData;
    procedure DisplayHeader(AIndex: Integer);
    procedure DisplayResProps(AItem: TResourceItem); overload;
    procedure DisplayResProps(AItem: TTreeNode); overload;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.acOpenAccept(Sender: TObject);
begin
  if od.Execute then
    OpenFile(od.FileName);
end;

procedure TForm1.acSaveResAccept(Sender: TObject);
begin
  if sd.Execute then
    SaveResource(PE.Resources[PNodeData(ResTree.Selected.Data)^],sd.FileName);
end;

procedure TForm1.ClearControls;
begin
  DFM.Lines.Clear;
  HexBox.Items.Clear;
  ObjectBox.Items.Clear;
  FuncBox.Items.Clear;
  CVList.Items.Clear;
  Memo.Lines.Clear;
end;

procedure TForm1.DebugListSelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  if not Assigned(Item) then
    Exit;
  CVList.Items.Clear;  
  with PE.Debugs[Item.Index] do
    case Typ of
      IMAGE_DEBUG_TYPE_CODEVIEW: begin
        with CVList.Items.Add do begin
          Caption:='Signature';
          SubItems.Add(Copy(PChar(@Signature),1,4));
        end;  
        with CVList.Items.Add do begin
          Caption:='Age';
          SubItems.Add(IntToStr(Age));
        end;
        with CVList.Items.Add do begin
          Caption:='PDB Filename';
          SubItems.Add(PDBFilename);
        end;
      end;
    IMAGE_DEBUG_TYPE_MISC: begin
      with CVList.Items.Add do begin
        Caption:='DBG Filename';
        SubItems.Add(PDBFilename);
      end;
    end;
  end;
end;

procedure TForm1.DisplayData;
var
  i,j: Integer;
  s: string;
  r,n: TTreeNode;
  d: PNodeData;
begin
  tsHeader.Tabs.Clear;
  tsHeader.Tabs.Add(' DOS ');
  tsHeader.Tabs.Add(' File ');
  if PE.Signature=LoWord(IMAGE_NT_SIGNATURE) then
    tsHeader.Tabs.Add(' Optional ');
  if PE.CLRHeaderCount>0 then begin
    tsHeader.Tabs.Add(' CLR ');
    tsHeader.Tabs.Add(' Metadata ');
  end;
  tsHeader.TabIndex:=1;

  DisplayHeader(tsHeader.TabIndex);

  with VerList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.VersionCount-1 do
        with Add do begin
          Caption:=PE.VersionNames[i];
          SubItems.Add(PE.VersionValues[i]);
        end;
    finally
      EndUpdate;
    end;
  end;

  with SecList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.SectionCount-1 do
        with Add, PE.Sections[i] do begin
          Caption:=Name;
          SubItems.Add(Format('%8.8x',[Data.VirtualAddress]));
          SubItems.Add(Format('%d',[Data.Misc.VirtualSize]));
          SubItems.Add(Format('%8.8x',[Data.PointerToRawData]));
          SubItems.Add(Format('%d',[Data.SizeOfRawData]));
          SubItems.Add(Format('%8.8x',[Data.Characteristics]));
        end;
    finally
      EndUpdate;
    end;
    sbSec.SimpleText:=Format('%d item(s)',[PE.SectionCount]);
  end;

  if PE.SectionCount>0 then
  with DirList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.DirectoryCount-1 do
        if PE.Directories[i].Data.Size>0 then
          with Add, PE.Directories[i] do begin
            Caption:=Name;
            SubItems.Add(Format('%8.8x',[Data.VirtualAddress]));
            SubItems.Add(Format('%d',[Data.Size]));
            SubItems.Add(Section);
          end;
    finally
      EndUpdate;
    end;
    sbDir.SimpleText:=Format('%d item(s)',[PE.DirectoryCount]);
  end;

  with ExportList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.ExportCount-1 do
        with Add, PE.ExportItems[i] do begin
          Caption:=Name;
          SubItems.Add(Format('%d',[Ordinal]));
          SubItems.Add(Format('%8.8x',[Address]));
        end;
    finally
      EndUpdate;
    end;
    sbExp.SimpleText:=Format('%d item(s)',[PE.ExportCount]);
  end;

  with ImportBox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.ImportCount-1 do
        Add(Format('%s (%d)',[PE.ImportItems[i].Name,Length(PE.ImportItems[i].Functions)]));
    finally
      EndUpdate;
    end;
    sbImp.SimpleText:=Format('%d item(s)',[PE.ImportCount]);
  end;

  with ResTree, Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.ResourceCount-1 do begin
        r:=GetFirstNode;
        while Assigned(r) do begin
          if SameText(r.Text,PE.Resources[i].Typename) then
            Break;
          r:=r.GetNextSibling;
        end;
        if not Assigned(r) then begin
          r:=AddChild(nil,PE.Resources[i].Typename);
          new(d);
          d^:=i;
          r.Data:=d;
        end;
        n:=AddChild(r,PE.Resources[i].Name);
        new(d);
        d^:=i;
        n.Data:=d;
      end;
    finally
      EndUpdate;
    end;
  end;

  with MDTree, Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.MetadataTableCount-1 do begin
        r:=AddChild(nil,PE.MetadataTables[i].Name);
        for j:=0 to High(PE.MetadataTables[i].Members) do begin
          n:=AddChild(r,PE.MetadataTables[i].Members[j]);
        end;
      end;
    finally
      EndUpdate;
    end;
  end;

  with DebugList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.DebugCount-1 do
        with Add, PE.Debugs[i] do begin
          Caption:=TypeName;
          SubItems.Add(Format('%d',[SizeOfData]));
          SubItems.Add(Format('0x%8.8x',[AddressOfRawData]));
          SubItems.Add(Format('0x%8.8x',[PointerToRawData]));
          SubItems.Add(Format('0x%8.8x',[Characteristics]));
          SubItems.Add(DateTimeToStr(Timestamp));
          SubItems.Add(Format('%d.%d',[MajorVersion,MinorVersion]));
        end;
    finally
      EndUpdate;
    end;
    sbDebug.SimpleText:=Format('%d item(s)',[PE.DebugCount]);
  end;

  with ExcList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.ExceptionCount-1 do
        with Add, PE.Exceptions[i] do
          if PE.Is64bit then begin
            Caption:=Format('0x%16.16x',[StartingAddress]);
            SubItems.Add(Format('0x%16.16x',[EndingAddress]));
            SubItems.Add(Format('0x%16.16x',[EndOfPrologue]));
          end else begin
            Caption:=Format('0x%8.8x',[StartingAddress]);
            SubItems.Add(Format('0x%8.8x',[EndingAddress]));
            SubItems.Add(Format('0x%8.8x',[EndOfPrologue]));
          end;
    finally
      EndUpdate;
    end;
    sbExc.SimpleText:=Format('%d item(s)',[PE.ExceptionCount]);
  end;

  with LCList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.LoadConfigCount-1 do
        with Add do begin
          Caption:=PE.LoadConfigNames[i];
          SubItems.Add(PE.LoadConfigValues[i]);
        end;
    finally
      EndUpdate;
    end;
  end;

  with TLSList.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.TLSCount-1 do
        with Add do begin
          Caption:=PE.TLSs[i];
          SubItems.Add(PE.TLSValues[i]);
        end;
    finally
      EndUpdate;
    end;
  end;

  with UnitBox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.UnitCount-1 do
        Add(PE.Units[i]);
    finally
      EndUpdate;
    end;
    sbUnit.SimpleText:=Format('%d item(s)',[PE.UnitCount]);
  end;

  with FormBox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.FormCount-1 do
        Add(PE.Forms[i]);
    finally
      EndUpdate;
    end;
    sbDFM.SimpleText:=Format('%d item(s)',[PE.FormCount]);
  end;

  with PkgBox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.PackageCount-1 do
        Add(PE.Packages[i]);
    finally
      EndUpdate;
    end;
    sbPkg.SimpleText:=Format('%d item(s)',[PE.PackageCount]);
  end;

  with ClassBox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to PE.ClassCount-1 do
        Add(PE.Classes[i].ClassName);
    finally
      EndUpdate;
    end;
    sbClass.SimpleText:=Format('%d item(s)',[PE.ClassCount]);
  end;

  if PE.IsPackageInfo then
  with FlagBox.Items do begin
    BeginUpdate;
    try
      Clear;
      s:='';
      if PE.PackageDescription<>'' then
        Add('Package description: '+PE.PackageDescription);
      if (PE.PackageFlags and pfNeverBuild<>0) then
        s:=s+'NeverBuild,';
      if (PE.PackageFlags and pfDesignOnly<>0) then
        s:=s+'DesignOnly,';
      if (PE.PackageFlags and pfRunOnly<>0) then
        s:=s+'RunOnly,';
      if (PE.PackageFlags and pfIgnoreDupUnits<>0) then
        s:=s+'IgnoreDupUnits,';
      SetLength(s,Length(s)-1);
      Add('Options: '+s);
      case PE.PackageFlags and pfModuleTypeMask of
        pfExeModule,
        pfModuleTypeMask: Add('Type: Executable');
        pfPackageModule: Add('Type: Package');
        pfLibraryModule: Add('Type: Library');
      end;
      case PE.PackageFlags and pfProducerMask of
        pfV3Produced: Add('Producer: Delphi 3 or C++ Builder 3');
        pfBCB4Produced: Add('Producer: C++ Builder 4 or later');
        pfDelphi4Produced: Add('Producer: Delphi 4 or later');
      end;
    finally
      EndUpdate;
    end;
  end;

  tsHdr.TabVisible:=PE.DOSHeaderCount>0;
  tsSec.TabVisible:=PE.SectionCount>0;
  tsDir.TabVisible:=PE.SectionCount>0;
  tsExp.TabVisible:=PE.ExportCount>0;
  tsImp.TabVisible:=PE.ImportCount>0;
  tsRes.TabVisible:=PE.ResourceCount>0;
  tsFlags.TabVisible:=PE.IsPackageInfo;
  tsUnits.TabVisible:=PE.UnitCount>0;
  tsForms.TabVisible:=PE.FormCount>0;
  tsClasses.TabVisible:=PE.ClassCount>0;
  tsPkgs.TabVisible:=PE.PackageCount>0;
  tsExp.TabVisible:=PE.ExportCount>0;
  tsVersion.TabVisible:=PE.VersionCount>0;
  tsDebug.TabVisible:=PE.DebugCount>0;
  tsExc.TabVisible:=PE.ExceptionCount>0;
  tsLoadConfig.TabVisible:=PE.LoadConfigCount>0;
  tsTLS.TabVisible:=PE.TLSCount>0;
  tsNETMD.TabVisible:=PE.MetadataTableCount>0;

  if not pc.ActivePage.TabVisible then
    pc.ActivePage:=tsHdr;

  Caption:=Format('Pirate EXE Explorer - [%s]',[PE.FileName]);
  Application.Title:=PE.Filename;
end;

procedure TForm1.DisplayHeader;
var
  i: Integer;
begin
  MDSList.Hide;
  with HdrList.Items do begin
    BeginUpdate;
    try
      Clear;
      case AIndex of
        0: for i:=0 to PE.DOSHeaderCount-1 do
             with Add do begin
               Caption:=PE.DOSHeaderNames[i];
               SubItems.Add(PE.DOSHeaderValues[i]);
             end;
        1: for i:=0 to PE.FileHeaderCount-1 do
             with Add do begin
               Caption:=PE.FileHeaderNames[i];
               SubItems.Add(PE.FileHeaderValues[i]);
             end;
        2: for i:=0 to PE.OptionaHeaderCount-1 do
             with Add do begin
               Caption:=PE.OptionalHeaderNames[i];
               SubItems.Add(PE.OptionalHeaderValues[i]);
             end;
        3: for i:=0 to PE.CLRHeaderCount-1 do
             with Add do begin
               Caption:=PE.CLRHeaderNames[i];
               SubItems.Add(PE.CLRHeaderValues[i]);
             end;
        4: begin
          for i:=0 to PE.MetadataHeaderCount-1 do
            with Add do begin
              Caption:=PE.MetadataHeaderNames[i];
              SubItems.Add(PE.MetadataHeaderValues[i]);
            end;
          MDSList.Items.Clear;
          for i:=0 to PE.MetadataStreamCount-1 do
            with MDSList.Items.Add do begin
              Caption:=PE.MetadataStreams[i].Name;
              SubItems.Add(Format('0x%8.8x',[PE.MetadataStreams[i].Address]));
              SubItems.Add(Format('%d',[PE.MetadataStreams[i].Size]));
            end;
          MDSList.Show;
        end;
      end;
    finally
      EndUpdate;
    end;
  end;
end;

procedure TForm1.DisplayResProps(AItem: TTreeNode);
begin
  if not Assigned(AItem) then
    Exit;
  with ResPropList, Items do begin
    BeginUpdate;
    try
      Clear;
      with Add do begin
        Caption:='Count';
        SubItems.Add(IntToStr(AItem.Count));
      end;
    finally
      EndUpdate;
    end;
  end;
end;

procedure TForm1.DisplayResProps(AItem: TResourceItem);
begin
  with ResPropList, Items do begin
    BeginUpdate;
    try
      Clear;
      with Add do begin
        Caption:='Name';
        SubItems.Add(AItem.Name);
      end;
      with Add do begin
        Caption:='Type';
        SubItems.Add(AItem.TypeName);
      end;
      with Add do begin
        Caption:='Language';
        SubItems.Add(AItem.Lang);
      end;
      with Add do begin
        Caption:='Code page';
        SubItems.Add(IntToStr(AItem.CodePage));
      end;
      with Add do begin
        Caption:='Raw data offset';
        SubItems.Add(Format('0x%8.8x',[AItem.RawDataOffset]));
      end;
      with Add do begin
        Caption:='Raw data size';
        SubItems.Add(Format('%d B',[AItem.RawDataSize]));
      end;

    finally
      EndUpdate;
    end;
  end;
end;

procedure TForm1.Exit1Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.FormBoxClick(Sender: TObject);
var
  i,idx: Integer;
  s: string;
begin
  for i:=0 to PE.FormCount-1 do
    if SameText(PE.Forms[i],FormBox.Items[FormBox.ItemIndex]) then begin
      idx:=i;
      Break;
    end;
  ObjectBox.Items.Clear;
  PE.GetFormSource(idx,DFM.Lines);
  for i:=0 to DFM.Lines.Count-1 do begin
    s:=Trim(DFM.Lines[i]);
    if Pos('object ',s)=1 then begin
      s:=Trim(Copy(s,Pos(':',s)+1,255));
      if (ObjectBox.Items.IndexOf(s)=-1) and not SameText(FormBox.Items[FormBox.ItemIndex],s) then
        ObjectBox.Items.Add(s);
    end;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DeleteFile(FFN);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  PE:=TPirate_PE.Create;
  pc.ActivePage:=tsHdr;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  if FileExists(ParamStr(1)) then
    OpenFile(ParamStr(1));
end;

procedure TForm1.cmViewResAs(Sender: TObject);
begin
  ResetControls;
  ViewResourceAs(TViewType(TComponent(Sender).Tag),PE.Resources[PNodeData(ResTree.Selected.Data)^]);
end;

procedure TForm1.HexListBox(ABox: TListBox; AData: Pointer;
  ASize: Cardinal);
var
  DumpData: PByte;
  Address, EndAddress: Integer;
  Hex, Ascii: string;
  i,j: Integer;
begin
  if ASize>65536 then begin
    ASize:=65536;
    MessageDlg('Resource is too big and it will be truncated for viewing.',mtWarning,[mbOK],0);
  end;
  try
  with ABox.Items do begin
    BeginUpdate;
    try
      Clear;
      for i:=0 to (ASize-1) div 16+1 do begin
        DumpData:=PByte(DWORD(AData)+DWORD(i*16));
        Address:=i*16;
        EndAddress:=ASize-1;
        SetLength(Hex,3*16);
        SetLength(Ascii,3*16);
        Hex:='';
        Ascii:='';
        for j:=0 to 15 do begin
          Hex:=Hex+Format('%.2x ',[DumpData^]);
          if DumpData^>=32 then
            Ascii:=Ascii+Chr(DumpData^)
          else
            Ascii:=Ascii+'.';
          Inc(DumpData);
          if Address+j>=EndAddress then
            Break;
        end;
        Add(Format('%8.8x  %s  %s',[Address,Hex,Ascii]));
      end;
    finally
      EndUpdate;
    end;
  end;
  except

  end;
end;

procedure TForm1.ImportBoxClick(Sender: TObject);
var
  i,idx: Integer;
begin
  if ImportBox.ItemIndex=-1 then
    Exit;

  for i:=0 to PE.ImportCount-1 do
    if Pos(PE.ImportItems[i].Name,ImportBox.Items[ImportBox.ItemIndex])=1 then begin
      idx:=i;
      Break;
    end;
  with FuncBox.Items do begin
    BeginUpdate;
    try
      Clear;
      with PE.ImportItems[idx] do
        for i:=0 to High(Functions) do
          if Functions[i].Name='' then
            Add(IntToStr(Functions[i].Ordinal))
          else
            Add(Functions[i].Name);
    finally
      EndUpdate;
    end;
  end;
end;

procedure TForm1.LoadResourceToView;
var
  p: Pointer;
  vt: TViewType;
begin
  Screen.Cursor:=crHourglass;
  try
    case ResItem.Typ of
      Longint(RT_MANIFEST),
      Longint(RT_HTML),
      Longint(RT_STRING),
      Longint(RT_MESSAGETABLE),
      Longint(RT_ACCELERATOR),
      Longint(RT_MENU),
      Longint(RT_DIALOG),
      Longint(RT_REGISTRY): if PE.SectionExists(SUPXSectionTag,p) then
                            vt:=vtHex
                          else
                            vt:=vtText;
      Longint(RT_ICON),
      Longint(RT_CURSOR): vt:=vtICO;
      Longint(RT_BITMAP): if PE.SectionExists(SUPXSectionTag,p) then
                            vt:=vtHex
                          else
                            vt:=vtBMP;
      else vt:=vtHex
    end;
    try
      ViewResourceAs(vt,ResItem)
    except
      ViewResourceAs(vtHex,ResItem);
    end;
  finally
    Screen.Cursor:=crDefault;
  end;
end;

procedure TForm1.OpenFile(AFilename: string);
begin
  ClientPanel.Hide;
  ResPropList.Items.Clear;
  ResetControls;
  ClearControls;
  Screen.Cursor:=crHourglass;
  try
    try
      PE.FileName:=AFilename;
    except
      Caption:='Pirate EXE Explorer - File is not in supported format.';
      Application.Title:=Caption;
      Exit;
    end;
    DisplayData;
    ClientPanel.Show;
  finally
    Screen.Cursor:=crDefault;
  end;
end;

procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin
  pmViewAs.Enabled:=ResTree.Selected.Level=1;
end;

procedure TForm1.ResetControls;
begin
  HexPanel.Hide;
  MemoPanel.Hide;
  ImagePanel.Hide;
end;

procedure TForm1.ResTreeChange(Sender: TObject; Node: TTreeNode);
begin
  DeleteFile(FFN);
  ResetControls;
  if Node.Level=1 then begin
    DisplayResProps(PE.Resources[PNodeData(Node.Data)^]);
    ResPropList.Update;
    LoadResourceToView(PE.Resources[PNodeData(Node.Data)^]);
    mmSaveRes.Enabled:=True;
  end else begin
    mmSaveRes.Enabled:=False;
    DisplayResProps(Node);
  end;
end;

procedure TForm1.ResTreeDeletion(Sender: TObject; Node: TTreeNode);
begin
  if Assigned(Node.Data) then
    Dispose(Node.Data);
end;

procedure TForm1.SaveResource(ResItem: TResourceItem; AFilename: string);
var
  rs: TResourceRawStream;
begin
  rs:=TResourceRawStream.Create(ResItem);
  try
    case ResItem.Typ of
      Longint(RT_STRING),
      Longint(RT_DIALOG),
      Longint(RT_MESSAGETABLE),
      Longint(RT_ACCELERATOR),
      Longint(RT_MENU): Memo.Lines.SaveToFile(AFilename);
      Longint(RT_ICON),
      Longint(RT_CURSOR),
      Longint(RT_BITMAP): Image.Picture.SaveToFile(AFilename);
      else rs.SaveToFile(AFilename);
    end;
  finally
    rs.Free;
  end;
end;

procedure TForm1.tsHeaderChange(Sender: TObject; NewTab: Integer;
  var AllowChange: Boolean);
begin
  DisplayHeader(NewTab);
end;

procedure TForm1.ViewResourceAs(AView: TViewType; ResItem: TResourceItem);
var
  rs: TResourceRawStream;
  ms: TMemoryStream;
p: Pointer;
begin
  ClearControls;
  try
    rs:=TResourceRawStream.Create(ResItem);
    ms:=TMemoryStream.Create;
    case AView of
      vtHex: begin
        HexListBox(HexBox,rs.Memory,rs.Size);
        HexPanel.Show;
      end;
      vtText: begin
        case ResItem.Typ of
          Longint(RT_STRING): SaveResourceAsStrings(ResItem,Memo.Lines);
          Longint(RT_MENU): SaveResourceAsMenu(ResItem,Memo.Lines);
          Longint(RT_DIALOG): SaveResourceAsDialog(ResItem,Memo.Lines);
          Longint(RT_MESSAGETABLE): SaveResourceAsMessageTable(ResItem,Memo.Lines);
          Longint(RT_ACCELERATOR): SaveResourceAsAccelerators(ResItem,Memo.Lines);
          else SaveResourceAsText(ResItem,Memo.Lines);
        end;
        Memo.SelStart:=0;
        Memo.SelLength:=0;
        MemoPanel.Caption:=Format('%d line(s)',[Memo.Lines.Count]);
        MemoPanel.Show;
      end;
      vtBMP: begin
        try
          SaveResourceAsBitmap(ResItem,ms);
          Image.Picture.Bitmap.LoadFromStream(ms);
          ImagePanel.Show;
        except
          ViewResourceAs(vtHex,ResItem);
        end;
      end;
      vtICO: begin
        try
          Image.Picture.Icon.Handle:=CreateIconFromResource(rs.Memory,rs.Size,ResItem.Typ=Longint(RT_ICON),$30000);
          ImagePanel.Show;
        except
          ViewResourceAs(vtHex,ResItem);
        end;
      end;
    end;
  finally
    rs.Free;
    ms.Free;
  end;
end;

end.
