
unit RXMain;

{ This program provides an example of how to use the TreeView and ListView
  components in a fashion similar to the Microsoft Windows Explorer.

  It is not intended to be a fully functional resource viewer. }

interface

uses
  Forms, SysUtils, Menus, Controls, Dialogs, ExtCtrls, MPlayer, StdCtrls,
  ComCtrls, Buttons, FileCtrl, Classes, Mover, ExeImage, HexDump;

type
  TMainForm = class(TForm)
    StatusBar: TStatusBar;
    TreeViewPanel: TPanel;
    Panel1: TPanel;
    ImageViewer: TImage;
    ListView: TListView;
    TreeView: TTreeView;
    Notebook: TNotebook;
    ListViewPanel: TPanel;
    FileOpenDialog: TOpenDialog;
    FileSaveDialog: TSaveDialog;
    Small: TImageList;
    Large: TImageList;
    DLB1: TDirectoryListBox;
    FLB1: TFileListBox;
    Panel2: TPanel;
    DriveComboBox1: TDriveComboBox;
    FilterComboBox1: TFilterComboBox;
    PopupMenu1: TPopupMenu;
    Saveresource1: TMenuItem;
    PopupMenu2: TPopupMenu;
    Saveas1: TMenuItem;
    Fullexpand1: TMenuItem;
    Fullcollapse1: TMenuItem;
    Mover1: TMover;
    Mover3: TMover;
    Mover2: TMover;
    VIList: TListView;
    Label1: TLabel;
    Panel3: TPanel;
    Panel4: TPanel;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    SpeedButton4: TSpeedButton;
    SpeedButton5: TSpeedButton;
    Panel5: TPanel;
    Panel6: TPanel;
    MPlayer: TMediaPlayer;
    ListViewCaption: TPanel;
    Panel7: TPanel;
    OpenBtn: TSpeedButton;
    SaveResBtn: TSpeedButton;
    Bevel1: TBevel;
    FlbSwBtn: TSpeedButton;
    AboutBtn: TSpeedButton;
    Bevel2: TBevel;
    SpeedButton6: TSpeedButton;
    Bevel3: TBevel;
    Label2: TLabel;
    Label3: TLabel;
    Memo1: TMemo;
    StringViewer: TRichEdit;
    procedure FileExit(Sender: TObject);
    procedure FileOpen(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ListViewEnter(Sender: TObject);
    procedure SaveResource(Sender: TObject);
    procedure SelectListViewType(Sender: TObject);
    procedure ShowAboutBox(Sender: TObject);
    procedure ToggleStatusBar(Sender: TObject);
    procedure TreeViewChange(Sender: TObject; Node: TTreeNode);
    {procedure SplitterMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);}
    {procedure SplitterMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);}
    {procedure SplitterMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);}
    {procedure ViewMenuDropDown(Sender: TObject);}
    procedure NotebookEnter(Sender: TObject);
    procedure FLB1Change(Sender: TObject);
    procedure TreeViewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Fullexpand1Click(Sender: TObject);
    procedure Fullcollapse1Click(Sender: TObject);
    procedure PopupMenu2Popup(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ListViewChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure MPlayerNotify(Sender: TObject);
    procedure ListViewPanelResize(Sender: TObject);
  private
    FExeFile  : TExeImage;
    HexDump   : THexDump;
    MediaFile : string;
    isUpdating: Boolean;
    //SplitControl: TSplitControl;
    procedure LoadResources(ResList: TResourceList; Node: TTreeNode);
    procedure DisplayResources;
    procedure UpdateViewPanel;
    procedure UpdateListView(ResList: TResourceList);
    procedure UpdateStatusLine(ResItem: TResourceItem);
    procedure MyOnClose(Sender: tObject; var Action: TCloseAction);
    procedure MyMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    //
    procedure SetFile(const aName: string);
    procedure SetEC(const aErrorCaption: string);
    //
    property ErrorCaption: string write SetEC;
  end;

var
  MainForm: TMainForm;

implementation

uses About, RXTypes, HomeTool{, Url}{, TypInfo}, Windows, Messages, Graphics;

{$R *.DFM}
{$R RXIMAGES.RES}

const
  itBitmap: TResType = Controls.rtBitmap; // Reference for duplicate identifier
  ImageMap: array[TResourceType] of Byte = (2,4,5,3,2,2,2,2,2,2,2,2,2,2,2,2,2);
  ResFiltMap: array[TResourceType] of Byte = (1,4,2,3,1,1,1,1,1,1,1,1,1,1,1,1,1);

  SCopyright     = 'Copyright © 1996 Borland International (Modified by Alek Oct, Nov 1997)';
  SNoResSelected = 'No resource selected';
  SFormCaption   = 'Resource Explorer';
  DefExt	 : array[TResourceType] of string = ('Dat', 'Cur', 'Bmp', 'Ico', 'Mnu', 'Dlg', 'Str', 'Fnt', 'Fnt', 'Acc', 'RCD', 'Msg', 'Cur', 'U13', 'Ico', 'U15', 'Ver');
  SSaveFilter    = 'Other Resource (*.*)|*.*|Bitmaps (*.BMP)|*.BMP|'+
		   'Icons (*.ICO)|*.ICO|Cursor (*.CUR)|*.CUR';
  SOpenFilter    = 'Executable File Images (*.EXE;*.DLL)|*.EXE;*.DLL|'+
		   'All Files (*.*)|*.*';

{ Utility Functions }

procedure Error(const ErrMsg: string);
begin
  raise Exception.Create(ErrMsg);
end;

procedure ErrorFmt(const ErrMsg: string; Params: array of const);
begin
  raise Exception.Create(format(ErrMsg, Params));
end;

function Confirm(const AMsg: String): Boolean;
begin
  Result := MessageDlg(AMsg, mtConfirmation, mbYesNoCancel, 0) = mrYes;
end;

{ Non Event Handlers }

procedure TMainForm.LoadResources(ResList: TResourceList; Node: TTreeNode);
var
  I: Integer;
  CNode: TTreeNode;
begin
  if Assigned(ResList) then
    for I := 0 to ResList.Count - 1 do
      with ResList[I] do begin
	CNode := TreeView.Items.AddChildObject(Node, Name, ResList[I]);
	if IsList then begin
	  CNode.SelectedIndex := 1;
	  LoadResources(List, CNode);
	end
	else begin
	  CNode.ImageIndex := ImageMap[ResList[I].ResType];
	  CNode.SelectedIndex := CNode.ImageIndex;
	end;
      end;
end;

procedure TMainForm.DisplayResources;
begin
  ListView.Items.Clear;
  TreeView.Selected := nil;
  TreeView.Items.Clear;
  LoadResources(FExeFile.Resources, nil);
  if (FExeFile.Error = 3) then ErrorCaption := 'No resources.'
  else begin
    Caption := Format('%s - %s', [SFormCaption, LowerCase(FExeFile.FileName)]);
    with TreeView do begin
      SetFocus;
      if (Items.Count > 0) then Selected := Items[0];
    end;
  end;
end;

{type
  tMyForm = class(tForm)
  public
    procedure ReadState(Reader: tReader); override;
  end;

procedure tMyForm.ReadState;
begin
  inherited;
end;

  {tMyOutStream = class(tMemoryStream)
  end;}

function MyDlgProc(aDlg: hWnd; aMsg: uInt; awParam: wParam; alParam: lParam): uInt; stdcall;
begin
  Result := 0;
  case aMsg of
    wm_InitDialog: ;
    wm_Command     : if (awParam = idCancel) then DestroyWindow(aDlg);
   // wm_RButtonDown : DestroyWindow(aDlg);
  end;
end;

procedure TMainForm.MyOnClose(Sender: tObject; var Action: TCloseAction);
var
  lF: tForm;
begin
  lF := (Sender as tForm);
  DestroyWindow(lF.Tag);
  lF.Free;
end;

function GetTMPFileName(Prefix: pChar; DoCreate: Boolean): string;
var
  lTempPath: array[0..MAX_PATH] of Char;
  lNumber  : Integer;
begin
  if (GetTempPath(SizeOf(lTempPath), lTempPath) < 1) then lTempPath := '.\';
  if DoCreate then lNumber := 0 else lNumber := 1973;
  if (GetTempFileName(lTempPath, Prefix, lNumber, lTempPath) < 1) then lTempPath := '_temp_.$$$';
  Result := lTempPath;
end;

procedure TMainForm.UpdateViewPanel;
var
  VIBuf : Pointer;
  R	: TResourceItem;

  procedure AddVI(Index: Integer; const aVIStr: string);
  type
    tVIBuf = array[0..1024] of Char;
  var
    lVIB  : ^tVIBuf;
    lZ    : Integer;
    lS    : string;
    lA    : array[0..120] of Char;

    function iH(Index: Integer): string;
    begin
      Result := IntToHex(Byte(lVIB[Index]), 2);
    end;

    function GetHex: string;
    begin
      Result := iH(1) + iH(0) + iH(3) + iH(2);
    end;

  begin
    lS := '';
    StrPCopy(lA, '\VarFileInfo\Translation');
    if not VerQueryValue(VIBuf, lA, Pointer(lVIB), lZ) then lZ := 0;
    if (lZ > 3) then begin
      Label3.Caption := 'Lang-charset: ' + GetHex;
      StrPCopy(lA, '\StringFileInfo\' + GetHex + '\' + aVIStr);
      if not VerQueryValue(VIBuf, lA, Pointer(lVIB), lZ) then lZ := 0;
      if (lZ > 0) then begin
	SetLength(lS, lZ);
	Move(lVIB^[0], lS[1], lZ);
      end;
    end;
    VIList.Items[Index].SubItems[0] := lS;
  end;

  procedure AssignPicture(aType: Byte);
  begin
    case aType of
      1: ImageViewer.Picture.Bitmap.Assign(R);
      2: ImageViewer.Picture.Assign(R);
      3: ImageViewer.Picture.Icon.Assign(R);
    end;
    Notebook.PageIndex := 1;
  end;

  function Long2Hex(aInt: Integer): string;
  type
    tLong = record
      L: Word;
      H: Word;
    end;
  begin
    Result := IntToHex(tLong(aInt).H, 4) + '.' + IntToHex(tLong(aInt).L, 4);
  end;

  type
    tIStr = record
      V: Integer;
      A: string;
    end;

  function FF2Str(Flags: Integer): string;
  type
    FFEnum = (eVS_FF_DEBUG, eVS_FF_PRERELEASE, eVS_FF_PATCHED,
	      eVS_FF_PRIVATEBUILD, eVS_FF_INFOINFERRED, eVS_FF_SPECIALBUILD);
  const
    fFStr: array[FFEnum] of tIStr =
      ((V: VS_FF_DEBUG;		A: 'Debug'),
       (V: VS_FF_PRERELEASE;	A: 'Pre-release'),
       (V: VS_FF_PATCHED;	A: 'Patched'),
       (V: VS_FF_PRIVATEBUILD;	A: 'Private build'),
       (V: VS_FF_INFOINFERRED;  A: 'Info inferred'),
       (V: VS_FF_SPECIALBUILD;	A: 'Special build'));
  var
    i: FFEnum;
  begin
    Result := '';
    for i := Low(i) to High(i) do
      if ((fFStr[i].V and Flags) <> 0) then Result := Result + fFStr[i].A + ' ';
    if (Result = '') then Result := '<none>';
  end;

  function OS2Str(Flags: Integer): string;
  type
    OSEnum = (eVOS_UNKNOWN, eVOS_DOS, eVOS_OS216, eVOS_OS232, eVOS_NT, eVOS__WINDOWS16, eVOS__PM16, eVOS__PM32, eVOS__WINDOWS32);
  const
    fOSStr: array[OSEnum] of tIStr =
      ((V: VOS_UNKNOWN;		A: 'Unknown'),
       (V: VOS_DOS;		A: 'DOS'),
       (V: VOS_OS216;		A: 'OS/2 16'),
       (V: VOS_OS232;		A: 'OS/2 32'),
       (V: VOS_NT;		A: 'NT'),
       (V: VOS__WINDOWS16;	A: 'Win16'),
       (V: VOS__PM16;		A: 'PM 16'),
       (V: VOS__PM32;		A: 'PM 32'),
       (V: VOS__WINDOWS32;	A: 'Win32'));
  var
    i: OSEnum;
  begin
    Result := '';
    for i := Low(i) to High(i) do
      if (fOSStr[i].V = (Flags and $F0000)) then Result := fOSStr[i].A;
    for i := Low(i) to High(i) do
      if (fOSStr[i].V = (Flags and $F)) then Result := Result + ' with ' + fOSStr[i].A;
  end;

  function FT2Str(Flags, SubFlags: Integer): string;
  type
    FTEnum = (eVFT_UNKNOWN, eVFT_APP, eVFT_DLL, eVFT_DRV, eVFT_FONT, eVFT_VXD, eVFT_STATIC_LIB);
    FT2Enum = (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
    FT3Enum = (e31, e32, e33);
  const
    fFTStr: array[FTEnum] of tIStr =
      ((V: VFT_UNKNOWN;		A: 'Unknown'),
       (V: VFT_APP;		A: 'Application'),
       (V: VFT_DLL;		A: 'Dynamic-link library'),
       (V: VFT_DRV;		A: 'Device driver:'),
       (V: VFT_FONT;		A: 'Font-'),
       (V: VFT_VXD;		A: 'Virtual device'),
       (V: VFT_STATIC_LIB;	A: 'Static-link library'));
     fFT2Str: array[FT2Enum] of tIStr =
       ((V: VFT2_UNKNOWN;		A: 'Unknown'),
	(V: VFT2_DRV_PRINTER;		A: 'printer'),
	(V: VFT2_DRV_KEYBOARD;		A: 'keyboard'),
	(V: VFT2_DRV_LANGUAGE;		A: 'language'),
	(V: VFT2_DRV_DISPLAY;		A: 'display'),
	(V: VFT2_DRV_MOUSE;		A: 'mouse'),
	(V: VFT2_DRV_NETWORK;		A: 'network'),
	(V: VFT2_DRV_SYSTEM;		A: 'system'),
	(V: VFT2_DRV_INSTALLABLE;	A: 'installable'),
	(V: VFT2_DRV_SOUND;		A: 'sound'),
	(V: VFT2_DRV_COMM;		A: 'comm'));
     fFT3Str: array[FT3Enum] of tIStr =
       ((V: VFT2_FONT_RASTER;		A: 'raster'),
	(V: VFT2_FONT_VECTOR;		A: 'vector'),
	(V: VFT2_FONT_TRUETYPE;		A: 'true type'));
  var
    i: FTEnum;
    j: FT2Enum;
    k: FT3Enum;
  begin
    Result := '';
    for i := Low(i) to High(i) do
      if (fFTStr[i].V = Flags) then Result := fFTStr[i].A;
    if (Result <> '') and (Result[Length(Result)] = ':') then
      for j := Low(j) to High(j) do
	if (fFT2Str[j].V = SubFlags) then Result := Result + ' ' + fFT2Str[j].A;
    if (Result <> '') and (Result[Length(Result)] = '-') then
      for k := Low(k) to High(k) do
	if (fFT3Str[k].V = SubFlags) then Result := Result + ' ' + fFT3Str[k].A;
  end;

type
  tAviHdr = record
    ID1 : Integer;
    Size: Integer;
    ID2 : Integer;
    ID3 : Integer;
  end;

  tJPGHdr = record
    ID1: Integer;
    ID2: Integer;
  end;

  tBigArray	= array [Word] of Byte;

const
  FormS: array[1..4] of Char = 'TPF0';

var
  VISize: Integer;
  fHnd  : tHandle;
  fName : array[0..512] of Char;
  hDlg  : tHandle;
//  hGlb  : hGlobal;
  lP    : pDlgTemplate;
//  lPBig : ^tBigArray;
//  lDItem: pDlgItemTemplate;
  lpW   : ^Word;
  lAH   : ^tAviHdr;
  lPJPEG: ^tJPGHdr;
  lFVI  : pVSFixedFileInfo;
  lZ    : Integer;
  k     : Integer;
  FORMD : ^Integer;
  lRS	: tResourceStream;
  lOS   : tMemoryStream;
  lOS1  : tMemoryStream;
  lF    : tForm;
  //lA    : array[0..1024] of Char;
  {lR    : tReader;
  lF    : tMyForm;
  Flags : tFilerFlags;
  I     : Integer;
  lV    : tValueType;}

  (*procedure ReadProperty(AInstance: TPersistent);
  var
    I, J, L: Integer;
    Instance: TPersistent;
    PropInfo: PPropInfo;
    PropValue: TObject;
    PropPath: string;

    procedure HandleException(E: Exception);
    var
      Name: string;
    begin
      Name := '';
      if AInstance is TComponent then
	Name := TComponent(AInstance).Name;
      if Name = '' then Name := AInstance.ClassName;
      //raise EReadError.CreateFmt(SPropertyException, [Name, PropPath, E.Message]);
    end;

    procedure PropPathError;
    begin
      lR.SkipValue;
      ReadError(SInvalidPropertyPath);
    end;

  begin
    try
      PropPath := ReadStr;
      try
	I := 1;
	L := Length(PropPath);
	Instance := AInstance;
	FCanHandleExcepts := True;
	while True do
	begin
	  J := I;
	  while (I <= L) and (PropPath[I] <> '.') do Inc(I);
	  FPropName := Copy(PropPath, J, I - J);
	  if I > L then Break;
	  PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
	  if PropInfo = nil then PropertyError;
	  PropValue := nil;
	  if PropInfo^.PropType^.Kind = tkClass then
	    PropValue := TObject(GetOrdProp(Instance, PropInfo));
	  if not (PropValue is TPersistent) then PropPathError;
	  Instance := TPersistent(PropValue);
	  Inc(I);
	end;
	PropInfo := GetPropInfo(Instance.ClassInfo, FPropName);
	if PropInfo <> nil then ReadPropValue(Instance, PropInfo) else
	begin
	  { Cannot reliably recover from an error in a defined property }
	  FCanHandleExcepts := False;
	  Instance.DefineProperties(Self);
	  FCanHandleExcepts := True;
	  if FPropName <> '' then PropertyError;
	end;
      except
	on E: Exception do HandleException(E);
      end;
    except
      on E: Exception do
	if not FCanHandleExcepts or not Error(E.Message) then raise;
    end;
  end;

  procedure TReader.ReadPropValue(Instance: TPersistent; PropInfo: Pointer);
  const
    NilMethod: TMethod = (Code: nil; Data: nil);
  var
    PropType: PTypeInfo;
    Method: TMethod;

    procedure SetIntIdent(Instance: TPersistent; PropInfo: Pointer;
      const Ident: string);
    var
      I: Integer;
      V: Longint;
    begin
      for I := 0 to IntConstList.Count - 1 do
	with TIntConst(IntConstList[I]) do
	  if PPropInfo(PropInfo)^.PropType^ = IntegerType then
	    if IdentToInt(Ident, V) then
	    begin
	      SetOrdProp(Instance, PropInfo, V);
	      Exit;
	    end;
      PropValueError;
    end;

    procedure SetObjectIdent(Instance: TPersistent; PropInfo: Pointer;
      const Ident: string);
    var
      RootName, Name: string;
      P: Integer;
      Fixup: TPropFixup;
    begin
      RootName := '';
      Name := Ident;
      P := Pos('.', Ident);
      if P <> 0 then
      begin
	RootName := Copy(Ident, 1, P - 1);
	Name := Copy(Ident, P + 1, MaxInt);
      end;
      Fixup := TPropFixup.Create(Instance, Root, PropInfo, RootName, Name);
      if RootName = '' then
	FFixups.Add(Fixup) else
	GlobalFixupList.Add(Fixup);
    end;

  begin
    if PPropInfo(PropInfo)^.SetProc = nil then ReadError(SReadOnlyProperty);
    PropType := PPropInfo(PropInfo)^.PropType^;
    case PropType^.Kind of
      tkInteger:
	if NextValue = vaIdent then
	  SetIntIdent(Instance, PropInfo, ReadIdent) else
	  SetOrdProp(Instance, PropInfo, ReadInteger);
      tkChar:
	SetOrdProp(Instance, PropInfo, Ord(ReadChar));
      tkEnumeration:
	SetOrdProp(Instance, PropInfo, EnumValue(PropType, ReadIdent));
      tkFloat:
	SetFloatProp(Instance, PropInfo, ReadFloat);
      tkString, tkLString, tkWString:
	SetStrProp(Instance, PropInfo, ReadString);
      tkSet:
	SetOrdProp(Instance, PropInfo, ReadSet(PropType));
      tkClass:
	case NextValue of
	  vaNil:
	    begin
	      ReadValue;
	      SetOrdProp(Instance, PropInfo, 0)
	    end;
	  vaCollection:
	    begin
	      ReadValue;
	      ReadCollection(TCollection(GetOrdProp(Instance, PropInfo)));
	    end
	else
	  SetObjectIdent(Instance, PropInfo, ReadIdent);
	end;
      tkMethod:
	if NextValue = vaNil then
	begin
	  ReadValue;
	  SetMethodProp(Instance, PropInfo, NilMethod);
	end
	else
	begin
	  Method.Code :=  FindMethod(Root, ReadIdent);
	  Method.Data := Root;
	  if Method.Code <> nil then SetMethodProp(Instance, PropInfo, Method);
	end;
    end;
  end;

  procedure ReadProps;
  begin
    lR.ReadProperty(lF);
  end;*)

begin
  with TreeView do begin
    if Visible and Assigned(Selected) then begin
      R := TResourceItem(Selected.Data);
      if R.IsList then UpdateListView(R.List) else
      begin
	case R.ResType of
	  rtBitmap	: AssignPicture(1);
	  rtIconEntry,
	  rtCursorEntry : AssignPicture(3);
	  rtString,
	  rtMenu: begin
	    StringViewer.Lines.Assign(R);
	    StringViewer.SelStart := 0;
	    Notebook.PageIndex := 2;
	  end;
	  rtVersion: begin
	    StrPCopy(fName, FLB1.FileName);
	    VISize := GetFileVersionInfoSize(fName, fHnd);
	    if (VISize > 0) then begin
	      GetMem(VIBuf, VISize);
	      try
		Notebook.PageIndex := 4;
		if GetFileVersionInfo(fName, fHnd, VISize, VIBuf) then begin
		  AddVI(0, 'CompanyName');
		  AddVI(1, 'FileDescription');
		  AddVI(2, 'FileVersion');
		  AddVI(3, 'InternalName');
		  AddVI(4, 'LegalCopyright');
		  AddVI(5, 'OriginalFilename');
		  AddVI(6, 'ProductName');
		  AddVI(7, 'ProductVersion');
		end;
		if not VerQueryValue(VIBuf, '\', Pointer(lFVI), lZ) then lZ := 0;
		if (lZ > 0) then begin
		  VIList.Items[9].SubItems[0]  := Long2Hex(lFVI.dwStrucVersion);
		  VIList.Items[10].SubItems[0] := Long2Hex(lFVI.dwFileVersionMS) + '.' + Long2Hex(lFVI.dwFileVersionLS);
		  VIList.Items[11].SubItems[0] := Long2Hex(lFVI.dwProductVersionMS) + '.' + Long2Hex(lFVI.dwProductVersionLS);
		  VIList.Items[12].SubItems[0] := FF2Str(lFVI.dwFileFlagsMask and lFVI.dwFileFlags);
		  VIList.Items[13].SubItems[0] := OS2Str(lFVI.dwFileOS);
		  VIList.Items[14].SubItems[0] := FT2Str(lFVI.dwFileType, lFVI.dwFileSubtype);
		  VIList.Items[15].SubItems[0] := 'not done yet.'
		end;
	      finally
		fHnd := GetLastError;
		FreeMem(VIBuf, VISize);
	      end;
	    end;
	  end;
	  rtDialog: begin
	    StrPCopy(fName, FLB1.FileName);
	    fHnd := LoadLibrary(fName);
	    if (fHnd > 0) then try
	      lRS := tResourceStream.Create(fHnd, R.GoodName, RT_DIALOG);
	      lZ  := lRS.Size + 16;
	      GetMem(lP, lZ);
	      try
		FillChar(lP^, lZ, 0);
		lRS.Read(lP^, lRS.Size);
		//lPBig := Pointer(lP);
		k := lP.cdit;
		{while (k < lRS.Size) do begin
		  lDItem := @lPBig[k];
		  //lDItem.id := 0;
		  Break;
		end;}
		lF := tForm.Create(Application);
		lF.FormStyle := fsStayOnTop;
		repeat
		  hDlg := CreateDialogIndirectParam{DialogBoxIndirect}(fHnd, lP^{hGlb}, lF.Handle, @MyDlgProc, 1973);
		  if (hDlg < 1) then Dec(lP.cdit);
		until (hDlg > 0) or (lP.cdit < 1);
		if (hDlg > 0) then begin
		  lF.Tag := hDlg;
		  lF.OnClose := MyOnClose;
		  lF.OnMouseDown := MyMouseDown;
		  //lF.Top := ;
		  //lF.Left := Left + Notebook.Left + 15;
		  lF.Width := 500;
		  lF.Caption := 'I''m just a placeholder for dialog. Click to close';
		  if (lP.cdit <> k) then ErrorCaption := IntToStr(k - lP.cdit) + ' control(s) has been stripped.'
				    else ErrorCaption := 'Take a look!';
		  lF.Show;
		  ShowWindow(hDlg, SW_SHOW);
		end
		else begin
		  ErrorCaption := 'Unable to create this dialog, sorry.';
		  lF.Free;
		end;
	      finally
		FreeMem(lP, lZ);
		lRS.Free;
	      end;
	    finally
	      FreeLibrary(fHnd);
	    end
	    else ErrorCaption := 'Unable to load library: ' + fName;
	  end;
	  else begin
	    lPW    := R.RawData;
	    lAH    := R.RawData;
	    lpJPEG := R.RawData;
	    FORMD  := R.RawData;
	    if (lPW^ = Ord('B') + Ord('M') shl 8) then AssignPicture(1) else
	    if (lpJPEG.ID1 = $e0ffd8ff) and (lpJPEG.ID2 = $464a1000) then AssignPicture(2) else
	    if ((lAH.ID1 = $46464952) and (lAH.ID2 = $20495641)) then begin
	      MediaFile := GetTMPFileName('AVI', True);
	      R.SaveToFile(MediaFile);
	      Notebook.PageIndex := 6;
	      MPlayer.FileName := MediaFile;
	      MPlayer.DeviceType := dtAVIVideo;
	      MPlayer.Open;
	      MPlayer.Play;
	    end else
	    if (FORMD^ = Integer(FormS)) then begin
	      //StrPCopy(fName, FLB1.FileName);
	      //fHnd := LoadLibrary(fName);
	      //if (fHnd > 0) then try
		//StrPCopy(lA, R.ResTypeStr);
		//lRS := tResourceStream.Create(fHnd, R.Name, RT_RCDATA);
		lOS1 := tMemoryStream.Create;
		lOS1.Write(R.RawData^, R.Size);
		lOS  := tMemoryStream.Create;
		try
		  lOS1.Position := 0;
		  ObjectBinaryToText(lOS1, lOS);
		  lOS.Position := 0;
		  StringViewer.Lines.LoadFromStream(lOS);
		  Notebook.PageIndex := 2;
		  {lR := tReader.Create(lRS, 4096);
		  lR.ReadSignature;
		  lR.ReadPrefix(Flags, I);
		  lR.ReadStr; lR.ReadStr;
		  lF := tMyForm.CreateNew(nil);
		  ReadProps;}
		finally
		  lOS1.Free;
		  lOS.Free;
		  //lR.Free;
		end;
	      //finally
		//FreeLibrary(fHnd);
	      //end
	      //else ErrorCaption := 'Unable to load library: ' + fName + ' Er:' + IntToHex(GetLastError, 8);
	    end else
	    begin
	      HexDump.Address := R.RawData;
	      HexDump.DataSize := R.Size;
	      Notebook.PageIndex := 3;
	    end;
	  end;
	 end;
      end;
      UpdateStatusLine(R);
    end;
  end;
end;

procedure TMainForm.UpdateListView(ResList: TResourceList);
var
  I: Integer;
begin
  ListView.Items.Clear;
  for I := 0 to ResList.Count-1 do
    with ResList[I], ListView.Items.Add do
    begin
      Data := ResList[I];
      Caption := Name;
      SubItems.Add(Format('%.7x', [Offset]));
      SubItems.Add(Format('%.5x', [Size]));
      ImageIndex := ImageMap[ResType];
    end;
  Notebook.PageIndex := 0;
end;

procedure TMainForm.UpdateStatusLine(ResItem: TResourceItem);
begin
  if ResItem.IsList then begin
    ListViewCaption.Caption := ' ' + TreeView.Selected.Text;
    StatusBar.Panels[0].Text := Format(' %d object(s)', [ListView.Items.Count]);
    StatusBar.Panels[1].Text := Format(' Offset: %x', [ResItem.Offset]);
  end
  else with ResItem do begin
    ListViewCaption.Caption := {Format(' %s: %s', [ResTypeStr,} Name{])};
    StatusBar.Panels[0].Text := '';
    StatusBar.Panels[1].Text := Format(' Offset: %x  Size: %x', [Offset, Size]);
  end;
end;

{ Form Initialization }

const
  AppName	= 'ResourceExplorer';
  LastPathStr	= 'LastPath';

procedure TMainForm.FormCreate(Sender: TObject);
var
  lS: string;
begin
  //SplitControl := TSplitControl.Create(Self);
  HexDump := CreateHexDump(TWinControl(NoteBook.Pages.Objects[3]));
  FileOpenDialog.Filter := SOpenFilter;
  FileSaveDialog.Filter := SSaveFilter;
  Small.ResourceLoad(itBitmap, 'SmallImages', clOlive);
  Large.ResourceLoad(itBitmap, 'LargeImages', clOlive);
  Notebook.PageIndex := 5;
  if (ParamCount > 0) and FileExists(ParamStr(1)) then
  begin
    Show;
    FExeFile := TExeImage.Create(Self, ParamStr(1));
    if (fExeFile.Error <> 2) then DisplayResources
			     else ErrorCaption := 'Not a PE file.'
  end
  else begin
    lS := GetRegStr(AppName, LastPathStr, '');
    if (lS <> '') then DLB1.Directory := lS;
  end;
  FLB1.Mask := FilterComboBox1.Mask;
end;

{ Menu Event Handlers }

procedure TMainForm.SetFile(const aName: string);
var
  TmpExeFile: TExeImage;
begin
  if FileExists(aName) then begin
    isUpdating := True;
    TreeView.Items.Clear;
    isUpdating := False;
    TmpExeFile := TExeImage.Create(Self, aName);
    if Assigned(FExeFile) then FExeFile.Destroy;
    FExeFile := TmpExeFile;
    if (fExeFile.Error <> 2) then DisplayResources
			     else ErrorCaption := 'Not a PE file.'
  end;
end;

procedure TMainForm.FileOpen(Sender: TObject);
begin
  with FileOpenDialog do
    if Execute then SetFile(FileName);
end;

procedure TMainForm.FileExit(Sender: TObject);
begin
  Close;
end;

procedure TMainForm.ListViewEnter(Sender: TObject);
begin
  with ListView do
    if (Items.Count > 1) and (Selected = nil) then
    begin
      Selected := Items[0];
      ItemFocused := Selected;
    end;
end;

procedure TMainForm.SaveResource(Sender: TObject);
var
  ResItem: TResourceitem;

  function TreeViewResourceSelected: Boolean;
  begin
    Result := Assigned(TreeView.Selected) and
	      Assigned(TreeView.Selected.Data) and
	      not TResourceItem(TreeView.Selected.Data).IsList;
    if Result then ResItem := TResourceItem(TreeView.Selected.Data);
  end;

  function ListViewResourceSelected: Boolean;
  begin
    Result := Assigned(ListView.Selected) and
	      Assigned(ListView.Selected.Data) and
	      not TResourceItem(ListView.Selected.Data).IsList;
    if Result then ResItem := TResourceItem(ListView.Selected.Data);
  end;

begin
  if TreeViewResourceSelected or ListViewResourceSelected then
  with FileSaveDialog do begin
    FilterIndex := ResFiltMap[ResItem.ResType];
    FileName := ResItem.Name + '.' + DefExt[ResItem.ResType];
    if Execute then ResItem.SaveToFile(FileName);
  end
  else Error(SNoResSelected);
end;

procedure TMainForm.SelectListViewType(Sender: TObject);
begin
  ListView.ViewStyle := TViewStyle(TComponent(Sender).Tag);
end;

procedure TMainForm.ShowAboutBox(Sender: TObject);
begin
  AboutBtn.Down := True;
  About.ShowAboutBox;
  AboutBtn.Down := False;
end;

procedure TMainForm.ToggleStatusBar(Sender: TObject);
var
  lV: Boolean;
begin
  //StatusBar.Visible := not StatusBar.Visible;
  lV := FlbSwBtn.Down;
  if lV then begin
    Panel2.Show;
    Panel1.Show;
    Mover1.Show;
  end
  else begin
    Mover1.Hide;
    Panel1.Hide;
    Panel2.Hide;
  end;
end;

procedure TMainForm.TreeViewChange(Sender: TObject; Node: TTreeNode);
begin
  if Assigned(Node) and not Node.Deleting and not IsUpdating then UpdateViewPanel;
  {$B-}
  with TreeView do begin
    SaveResBtn.Enabled := Assigned(Selected) and (Selected.Count < 1);
    if Assigned(Selected) and (Selected.Count > 0) then Selected.Expand(True);
  end;
end;

{procedure TMainForm.ViewMenuDropDown(Sender: TObject);
var
  I: Integer;
begin
  miViewStatusBar.Checked := StatusBar.Visible;
  for I := 0 to miView.Count-1 do
    with miView.Items[I] do
      if GroupIndex = 1 then
	Checked := (Tag = Ord(ListView.ViewStyle));
end;}

{procedure TMainForm.SplitterMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if (Button = mbLeft) and (Shift = [ssLeft]) then
    SplitControl.BeginSizing(Splitter, TreeViewPanel);
end;}

{procedure TMainForm.SplitterMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  with SplitControl do if Sizing then ChangeSizing(X, Y);
end;}

{procedure TMainForm.SplitterMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  with SplitControl do if Sizing then EndSizing;
end;}

procedure TMainForm.NotebookEnter(Sender: TObject);
var
  Page: TWinControl;
begin
  with NoteBook do
  begin
    Page := TWinControl(Pages.Objects[PageIndex]);
    if (Page.ControlCount > 0) and (Page.Controls[0] is TWinControl) then
      TWinControl(Page.Controls[0]).SetFocus;
  end;
end;

procedure TMainForm.FLB1Change(Sender: TObject);
begin
  SetFile(FLB1.FileName);
end;

procedure TMainForm.TreeViewMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Node: tTreeNode;
begin
  Node := TreeView.GetNodeAt(X, Y);
  if Assigned(Node) and (Button = mbRight) then TreeView.Selected := Node;
end;

procedure TMainForm.Fullexpand1Click(Sender: TObject);
begin
  TreeView.FullExpand;
end;

procedure TMainForm.Fullcollapse1Click(Sender: TObject);
begin
  TreeView.FullCollapse;
end;

procedure TMainForm.PopupMenu2Popup(Sender: TObject);
begin
  {$B-}
  SaveAs1.Enabled := (Assigned(TreeView.Selected) and (TreeView.Selected.Count < 1)) or Assigned(ListView.Selected);
  Saveresource1.Enabled := SaveAs1.Enabled;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SetRegStr(AppName, LastPathStr, DLB1.Directory);
end;

procedure TMainForm.SetEC(const aErrorCaption: string);
begin
  Notebook.PageIndex := 5;
  Label1.Caption := aErrorCaption;
end;

procedure TMainForm.ListViewChange(Sender: TObject; Item: TListItem;
  Change: TItemChange);
begin
  SaveResBtn.Enabled := Assigned(ListView.Selected);
end;

procedure TMainForm.MPlayerNotify(Sender: TObject);
var
  lBuf: array[0..MAX_PATH] of Char;
begin
  MPlayer.Close;
  StrPCopy(lBuf, MediaFile);
  DeleteFile(lBuf);
  ErrorCaption := 'To play again, select again.';
end;

procedure TMainForm.ListViewPanelResize(Sender: TObject);
begin
  Memo1.Height := Notebook.Height - 40;
end;

procedure TMainForm.MyMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  (Sender as tForm).Close;
end;

end.
