Reversing Delphi Code


Let's look at the "Resxplor.dpr" project from your "\Borland\Delphi 2.0\Demos\Resxplor" directory:

In order to understand how this program works, we could either go through the follow six .pas files....

About.pas unit About;

interface

uses Windows, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, SysUtils;

type TAboutBox = class(TForm) OKButton: TButton; Panel1: TPanel; ProgramIcon: TImage; ProgramName: TLabel; Copyright: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end;

var AboutBox: TAboutBox;

procedure ShowAboutBox;

implementation

{$R *.DFM}

procedure ShowAboutBox; begin with TAboutBox.Create(Application) do try ShowModal; finally Free; end; end;

procedure TAboutBox.FormCreate(Sender: TObject); begin Caption := Format('About %s', [Application.Title]); ProgramIcon.Picture.Assign(Application.Icon); ProgramName.Caption := Application.Title; end;

end.

Exeimage.pas unit ExeImage;

interface

uses TypInfo, Classes, SysUtils, Windows, Graphics, RXTypes;

type

{ Exceptions }

EExeError = class(Exception);

{ Forward Declarations }

TResourceItem = class; TResourceClass = class of TResourceItem; TResourceList = class;

{ TExeImage }

TExeImage = class(TComponent) private FFileName: string; FFileHandle: THandle; FFileMapping: THandle; FFileBase: Pointer; FDosHeader: PIMAGE_DOS_HEADER; FNTHeader: PIMAGE_NT_HEADERS; FSections: TList; FResourceList: TResourceList; FIconResources: TResourceItem; FCursorResources: TResourceItem; FResourceBase: Longint; FResourceRVA: Longint; function GetResourceList: TResourceList; function GetSectionHdr(const SectionName: string; var Header: PIMAGE_SECTION_HEADER): Boolean; public constructor Create(AOwner: TComponent; const AFileName: string); destructor Destroy; property FileName: string read FFileName; property Resources: TResourceList read GetResourceList; end;

{ TResourceItem }

TResourceItem = class(TComponent) private FList: TResourceList; FDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; function DataEntry: PIMAGE_RESOURCE_DATA_ENTRY; function FExeImage: TExeImage; function FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; function GetResourceItem(Index: Integer): TResourceItem; function GetResourceType: TResourceType; protected function GetName: string; virtual; function GetResourceList: TResourceList; virtual; public constructor Create(AOwner: TComponent; ADirEntry: Pointer); function IsList: Boolean; virtual; function Offset: Integer; function Size: Integer; function RawData: Pointer; function ResTypeStr: string; procedure SaveToFile(const FileName: string); procedure SaveToStream(Stream: TStream); virtual; property Items[Index: Integer]: TResourceItem read GetResourceItem; default; property List: TResourceList read GetResourceList; property Name: string read GetName; property ResType: TResourceType read GetResourceType; end;

{ TIconResource }

TIconResource = class(TResourceItem) protected function GetResourceList: TResourceList; override; public function IsList: Boolean; override; end;

{ TIconResEntry }

TIconResEntry = class(TResourceItem) protected FResInfo: PIconResInfo; function GetName: string; override; procedure AssignTo(Dest: TPersistent); override; public procedure SaveToStream(Stream: TStream); override; end;

{ TCursorResource }

TCursorResource = class(TIconResource) protected function GetResourceList: TResourceList; override; end;

{ TCursorResEntry }

TCursorResEntry = class(TIconResEntry) protected FResInfo: PCursorResInfo; function GetName: string; override; end;

{ TBitmapResource }

TBitMapResource = class(TResourceItem) protected procedure AssignTo(Dest: TPersistent); override; public procedure SaveToStream(Stream: TStream); override; end;

{ TStringResource }

TStringResource = class(TResourceItem) protected procedure AssignTo(Dest: TPersistent); override; end;

{ TMenuResource }

TMenuResource = class(TResourceItem) private FNestStr: string; FNestLevel: Integer; procedure SetNestLevel(Value: Integer); protected procedure AssignTo(Dest: TPersistent); override; property NestLevel: Integer read FNestLevel write SetNestLevel; property NestStr: string read FNestStr; end;

{ TResourceList }

TResourceList = class(TComponent) protected FList: TList; FResDir: PIMAGE_RESOURCE_DIRECTORY; FExeImage: TExeImage; FResType: Integer; function List: TList; virtual; function GetResourceItem(Index: Integer): TResourceItem; public constructor Create(AOwner: TComponent; ResDirOfs: Longint; AExeImage: TExeImage); destructor Destroy; override; function Count: Integer; property Items[Index: Integer]: TResourceItem read GetResourceItem; default; end;

{ TIconResourceList }

TIconResourceList = class(TResourceList) protected function List: TList; override; end;

{ TCursorResourceList }

TCursorResourceList = class(TResourceList) protected function List: TList; override; end;

implementation

{ This function maps a resource type to the associated resource class }

function GetResourceClass(ResType: Integer): TResourceClass; const TResourceClasses: array[TResourceType] of TResourceClass = ( TResourceItem, { rtUnknown0 } TCursorResEntry, { rtCursorEntry } TBitmapResource, { rtBitmap } TIconResEntry, { rtIconEntry } TMenuResource, { rtMenu } TResourceItem, { rtDialog } TStringResource, { rtString } TResourceItem, { rtFontDir } TResourceItem, { rtFont } TResourceItem, { rtAccelerators } TResourceItem, { rtRCData } TResourceItem, { rtMessageTable } TCursorResource, { rtGroupCursor } TResourceItem, { rtUnknown13 } TIconResource, { rtIcon } TResourceItem, { rtUnknown15 } TResourceItem); { rtVersion } begin if (ResType >= Integer(Low(TResourceType))) and (ResType <= Integer(High(TResourceType))) then Result := TResourceClasses[TResourceType(ResType)] else Result := TResourceItem; end;

{ Utility Functions }

function Min(A, B: Integer): Integer; begin if A < B then Result := A else Result := B; end;

{ This function checks if an offset is a string name, or a directory } {Assumes: IMAGE_RESOURCE_NAME_IS_STRING = IMAGE_RESOURCE_DATA_IS_DIRECTORY}

function HighBitSet(L: Longint): Boolean; begin Result := (L and IMAGE_RESOURCE_DATA_IS_DIRECTORY) <> 0; end;

function StripHighBit(L: Longint): Longint; begin Result := L and IMAGE_OFFSET_STRIP_HIGH; end;

function StripHighPtr(L: Longint): Pointer; begin Result := Pointer(L and IMAGE_OFFSET_STRIP_HIGH); end;

{ This function converts a pointer to a wide char string into a pascal string }

function WideCharToStr(WStr: PWChar; Len: Integer): string; begin if Len = 0 then Len := lstrlenw(WStr); SetLength(Result, Len); WideCharToMultiByte(CP_ACP, 0, WStr, Len, PChar(Result), Len, nil, nil); end;

{ Exceptions }

procedure ExeError(const ErrMsg: string); begin raise EExeError.Create(ErrMsg); end;

{ TExeImage }

constructor TExeImage.Create(AOwner: TComponent; const AFileName: string); begin inherited Create(AOwner); FFileName := AFileName; FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if FFileHandle = INVALID_HANDLE_VALUE then ExeError('Couldn''t open: '+FFileName); FFileMapping := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil); if FFileMapping = 0 then ExeError('CreateFileMapping failed'); FFileBase := MapViewOfFile(FFileMapping, FILE_MAP_READ, 0, 0, 0); if FFileBase = nil then ExeError('MapViewOfFile failed'); FDosHeader := PIMAGE_DOS_HEADER(FFileBase); if not FDosHeader.e_magic = IMAGE_DOS_SIGNATURE then ExeError('unrecognized file format'); FNTHeader := PIMAGE_NT_HEADERS(Longint(FDosHeader) + FDosHeader.e_lfanew); if IsBadReadPtr(FNTHeader, sizeof(IMAGE_NT_HEADERS)) or (FNTHeader.Signature <> IMAGE_NT_SIGNATURE) then ExeError('Not a PE (WIN32 Executable) file'); end;

destructor TExeImage.Destroy; begin if FFileHandle <> INVALID_HANDLE_VALUE then begin UnmapViewOfFile(FFileBase); CloseHandle(FFileMapping); CloseHandle(FFileHandle); end; inherited Destroy; end;

function TExeImage.GetSectionHdr(const SectionName: string; var Header: PIMAGE_SECTION_HEADER): Boolean; var I: Integer; begin Header := PIMAGE_SECTION_HEADER(FNTHeader); Inc(PIMAGE_NT_HEADERS(Header)); Result := True; for I := 0 to FNTHeader.FileHeader.NumberOfSections - 1 do begin if Strlicomp(Header.Name, PChar(SectionName), IMAGE_SIZEOF_SHORT_NAME) = 0 then Exit; Inc(Header); end; Result := False; end;

function TExeImage.GetResourceList: TResourceList; var ResSectHdr: PIMAGE_SECTION_HEADER; begin if not Assigned(FResourceList) then begin if GetSectionHdr('.rsrc', ResSectHdr) then begin FResourceBase := ResSectHdr.PointerToRawData + Longint(FDosHeader); FResourceRVA := ResSectHdr.VirtualAddress; FResourceList := TResourceList.Create(Self, FResourceBase, Self); end else ExeError('No resources in this file.'); end; Result := FResourceList; end;

{ TResourceItem }

constructor TResourceItem.Create(AOwner: TComponent; ADirEntry: Pointer); begin inherited Create(AOwner); FDirEntry := ADirEntry; end;

function TResourceItem.DataEntry: PIMAGE_RESOURCE_DATA_ENTRY; begin Result := PIMAGE_RESOURCE_DATA_ENTRY(FirstChildDirEntry.OffsetToData + FExeImage.FResourceBase); end;

function TResourceItem.FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; begin Result := PIMAGE_RESOURCE_DIRECTORY_ENTRY(StripHighBit(FDirEntry.OffsetToData) + FExeImage.FResourceBase + SizeOf(IMAGE_RESOURCE_DIRECTORY)); end;

function TResourceItem.FExeImage: TExeImage; begin Result := (Owner as TResourceList).FExeImage; end;

function TResourceItem.GetResourceItem(Index: Integer): TResourceItem; begin Result := List[Index]; end;

function TResourceItem.GetResourceType: TResourceType; begin Result := TResourceType((Owner as TResourceList).FResType); end;

function TResourceItem.IsList: Boolean; begin Result := HighBitSet(FirstChildDirEntry.OffsetToData); end;

function TResourceItem.GetResourceList: TResourceList; begin if not IsList then ExeError('ResourceItem is not a list'); if not Assigned(FList) then FList := TResourceList.Create(Self, StripHighBit(FDirEntry.OffsetToData) + FExeImage.FResourceBase, FExeImage); Result := FList; end;

function TResourceItem.GetName: string; var PDirStr: PIMAGE_RESOURCE_DIR_STRING_U; begin { Check for Level1 entries, these are resource types. } if (Owner.Owner = FExeImage) and not HighBitSet(FDirEntry.Name) and (FDirEntry.Name <= 16) then begin Result := Copy(GetEnumName(TypeInfo(TResourceType), FDirEntry.Name), 3, 20); Exit; end;

if HighBitSet(FDirEntry.Name) then begin PDirStr := PIMAGE_RESOURCE_DIR_STRING_U(StripHighBit(FDirEntry.Name) + FExeImage.FResourceBase); Result := WideCharToStr(@PDirStr.NameString, PDirStr.Length); Exit; end; Result := Format('%d', [FDirEntry.Name]); end;

function TResourceItem.Offset: Integer; begin if IsList then Result := StripHighBit(FDirEntry.OffsetToData) else Result := DataEntry.OffsetToData; end;

function TResourceItem.RawData: Pointer; begin with FExeImage do Result := pointer(FResourceBase - FResourceRVA + DataEntry.OffsetToData); end;

function TResourceItem.ResTypeStr: string; begin Result := Copy(GetEnumName(TypeInfo(TResourceType), Ord(ResType)), 3, 20); end;

procedure TResourceItem.SaveToFile(const FileName: string); var FS: TFileStream; begin FS := TFileStream.Create(FileName, fmCreate); try Self.SaveToStream(FS); finally FS.Free; end; end;

procedure TResourceItem.SaveToStream(Stream: TStream); begin Stream.Write(RawData^, Size); end;

function TResourceItem.Size: Integer; begin if IsList then Result := 0 else Result := DataEntry.Size; end;

{ TBitmapResource }

procedure TBitmapResource.AssignTo(Dest: TPersistent); var MemStr: TMemoryStream; BitMap: TBitMap; begin if (Dest is TPicture) then begin BitMap := TPicture(Dest).Bitmap; MemStr := TMemoryStream.Create; try SaveToStream(MemStr); MemStr.Seek(0,0); BitMap.LoadFromStream(MemStr); finally MemStr.Free; end end else inherited AssignTo(Dest); end;

procedure TBitmapResource.SaveToStream(Stream: TStream);

function GetDInColors(BitCount: Word): Integer; begin case BitCount of 1, 4, 8: Result := 1 shl BitCount; else Result := 0; end; end;

var BH: TBitmapFileHeader; BI: PBitmapInfoHeader; BC: PBitmapCoreHeader; ClrUsed: Integer; begin FillChar(BH, sizeof(BH), #0); BH.bfType := $4D42; BH.bfSize := Self.Size + sizeof(BH); BI := PBitmapInfoHeader(RawData); if BI.biSize = sizeof(TBitmapInfoHeader) then begin ClrUsed := BI.biClrUsed; if ClrUsed = 0 then ClrUsed := GetDInColors(BI.biBitCount); BH.bfOffBits := ClrUsed * SizeOf(TRgbQuad) + sizeof(TBitmapInfoHeader) + sizeof(BH); end else begin BC := PBitmapCoreHeader(RawData); ClrUsed := GetDInColors(BC.bcBitCount); BH.bfOffBits := ClrUsed * SizeOf(TRGBTriple) + sizeof(TBitmapCoreHeader) + sizeof(BH); end; Stream.Write(BH, SizeOf(BH)); Stream.Write(RawData^, Self.Size); end;

{ TIconResource }

function TIconResource.GetResourceList: TResourceList; begin if not Assigned(FList) then FList := TIconResourceList.Create(Owner, LongInt(RawData), FExeImage); Result := FList; end;

function TIconResource.IsList: Boolean; begin Result := True; end;

{ TIconResEntry }

procedure TIconResEntry.AssignTo(Dest: TPersistent); var hIco: HIcon; begin if Dest is TPicture then begin hIco := CreateIconFromResource(RawData, Size, (ResType = rtIconEntry), $30000); TPicture(Dest).Icon.Handle := hIco; end else inherited AssignTo(Dest); end;

function TIconResEntry.GetName: string; begin if Assigned(FResInfo) then with FResInfo^ do Result := Format('%d X %d %d Colors', [bWidth, bHeight, bColorCount]) else Result := inherited GetName; end;

procedure TIconResEntry.SaveToStream(Stream: TStream); begin with TIcon.Create do try Handle := CreateIconFromResource(RawData, Self.Size, (ResType <> rtIcon), $30000); SaveToStream(Stream); finally Free; end; end;

{ TCursorResource }

function TCursorResource.GetResourceList: TResourceList; begin if not Assigned(FList) then FList := TCursorResourceList.Create(Owner, LongInt(RawData), FExeImage); Result := FList; end;

{ TCursorResEntry }

function TCursorResEntry.GetName: string; begin if Assigned(FResInfo) then with FResInfo^ do Result := Format('%d X %d %d Bit(s)', [wWidth, wWidth, wBitCount]) else Result := inherited GetName; end;

{ TStringResource }

procedure TStringResource.AssignTo(Dest: TPersistent); var P: PWChar; ID: Integer; Cnt: Integer; Len: Word; begin if (Dest is TStrings) then with TStrings(Dest) do begin BeginUpdate; try Clear; P := RawData; Cnt := 0; while Cnt < StringsPerBlock do begin Len := Word(P^); Inc(P); if Len > 0 then begin ID := ((FDirEntry.Name - 1) shl 4) + Cnt; Add(Format('%d, "%s"', [ID, WideCharToStr(P, Len)])); Inc(P, Len); end; Inc(Cnt); end; finally EndUpdate; end; end else inherited AssignTo(Dest); end;

{ TMenuResource }

procedure TMenuResource.SetNestLevel(Value: Integer); begin FNestLevel := Value; SetLength(FNestStr, Value * 2); FillChar(FNestStr[1], Value * 2, ' '); end;

procedure TMenuResource.AssignTo(Dest: TPersistent); var IsPopup: Boolean; Len: Word; MenuData: PWord; MenuEnd: PChar; MenuText: PWChar; MenuID: Word; MenuFlags: Word; S: string; begin if (Dest is TStrings) then with TStrings(Dest) do begin BeginUpdate; try Clear; MenuData := RawData; MenuEnd := PChar(RawData) + Size; Inc(MenuData, 2); NestLevel := 0; while PChar(MenuData) < MenuEnd do begin MenuFlags := MenuData^; Inc(MenuData); IsPopup := (MenuFlags and MF_POPUP) = MF_POPUP; if not IsPopup then begin MenuID := MenuData^; Inc(MenuData); end; MenuText := PWChar(MenuData); Len := lstrlenw(MenuText); if Len = 0 then S := 'MENUITEM SEPARATOR' else begin S := WideCharToStr(MenuText, Len); if IsPopup then S := Format('POPUP "%s"', [S]) else S := Format('MENUITEM "%s", %d', [S, MenuID]); end; Inc(MenuData, Len + 1); Add(NestStr + S); if (MenuFlags and MF_END) = MF_END then begin NestLevel := NestLevel - 1; Add(NestStr + 'ENDPOPUP'); end; if IsPopup then NestLevel := NestLevel + 1; end; finally EndUpdate; end; end else inherited AssignTo(Dest); end;

{ TResourceList }

constructor TResourceList.Create(AOwner: TComponent; ResDirOfs: Longint; AExeImage: TExeImage); var DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; begin inherited Create(AOwner); FExeImage := AExeImage; FResDir := Pointer(ResDirOfs); if AOwner <> AExeImage then if AOwner.Owner.Owner = AExeImage then begin DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir); inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry)); FResType := TResourceItem(Owner).FDirEntry.Name; end else FResType := (AOwner.Owner.Owner as TResourceList).FResType; end;

destructor TResourceList.Destroy; begin inherited Destroy; FList.Free; end;

function TResourceList.List: TList; var I: Integer; DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; DirCnt: Integer; ResItem: TResourceItem; begin if not Assigned(FList) then begin FList := TList.Create; DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir); inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry)); DirCnt := FResDir.NumberOfNamedEntries + FResDir.NumberOfIdEntries - 1; for I := 0 to DirCnt do begin { Handle Cursors and Icons specially } ResItem := GetResourceClass(FResType).Create(Self, DirEntry); if Owner = FExeImage then if (TResourceType(DirEntry.Name) in [rtCursorEntry, rtIconEntry]) then begin if TResourceType(DirEntry.Name) = rtCursorEntry then FExeImage.FCursorResources := ResItem else FExeImage.FIconResources := ResItem; Inc(DirEntry); Continue; end; FList.Add(ResItem); Inc(DirEntry); end; end; Result := FList; end;

function TResourceList.Count: Integer; begin Result := List.Count; end;

function TResourceList.GetResourceItem(Index: Integer): TResourceItem; begin Result := List[Index]; end;

{ TIconResourceList }

function TIconResourceList.List: TList; var I, J, Cnt: Integer; ResData: PIconResInfo; ResList: TResourceList; ResOrd: Integer; IconResource: TIconResEntry; begin if not Assigned(FList) then begin FList := TList.Create; Cnt := PIconHeader(FResDir).wCount; PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader); ResList := FExeImage.FIconResources.List; for I := 0 to Cnt - 1 do begin ResOrd := ResData.wNameOrdinal; for J := 0 to ResList.Count - 1 do begin if ResOrd = ResList[J].FDirEntry.Name then begin IconResource := ResList[J] as TIconResEntry; IconResource.FResInfo := ResData; FList.Add(IconResource); end; end; Inc(ResData); end; end; Result := FList; end;

{ TCursorResourceList }

function TCursorResourceList.List: TList; var I, J, Cnt: Integer; ResData: PCursorResInfo; ResList: TResourceList; ResOrd: Integer; CursorResource: TCursorResEntry; begin if not Assigned(FList) then begin FList := TList.Create; Cnt := PIconHeader(FResDir).wCount; PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader); ResList := FExeImage.FCursorResources.List; for I := 0 to Cnt - 1 do begin ResOrd := ResData.wNameOrdinal; for J := 0 to ResList.Count - 1 do begin if ResOrd = ResList[J].FDirEntry.Name then begin CursorResource := ResList[J] as TCursorResEntry; CursorResource.FResInfo := ResData; FList.Add(CursorResource); end; end; Inc(ResData); end; end; Result := FList; end;

end.

Hexdump.pas unit HexDump;

interface

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

const MAXDIGITS = 16;

{ THexDump }

type

THexStr = array[0..2] of Char; THexStrArray = array[0..MAXDIGITS-1] of THexStr;

THexDump = class(TCustomControl) private FActive: Boolean; FAddress: Pointer; FDataSize: Integer; FTopLine: Integer; FCurrentLine: Integer; FVisibleLines: Integer; FLineCount: Integer; FBytesPerLine: Integer; FItemHeight: Integer; FItemWidth: Integer; FFileColors: array[0..2] of TColor; FShowCharacters: Boolean; FShowAddress: Boolean; FBorder: TBorderStyle; FHexData: THexStrArray; FLineAddr: array[0..15] of char; FCharData: array[0..MAXDIGITS] of char;

procedure CheckActive; procedure CalcPaintParams; procedure SetTopLine(Value: Integer); procedure SetCurrentLine(Value: Integer); procedure SetFileColor(Index: Integer; Value: TColor); function GetFileColor(Index: Integer): TColor; procedure SetShowCharacters(Value: Boolean); procedure SetShowAddress(Value: Boolean); procedure SetBorder(Value: TBorderStyle); procedure SetAddress(Value: Pointer); procedure SetDataSize(Value: Integer); procedure AdjustScrollBars; function LineAddr(Index: Integer): PChar; function LineData(Index: Integer): PChar; function LineChars(Index: Integer): PChar; function ScrollIntoView: Boolean; procedure InvalidateLine(Index: Integer); procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED; procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER; procedure CMExit(var Message: TCMLostFocus); message CM_EXIT; procedure WMSize(var Message: TWMSize); message WM_SIZE; procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL; procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; protected procedure CreateParams(var Params: TCreateParams); override; procedure Paint; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property CurrentLine: Integer read FCurrentLine write SetCurrentLine; property Address: Pointer read FAddress write SetAddress; property DataSize: Integer read FDataSize write SetDataSize; published property Align; property Border: TBorderStyle read FBorder write SetBorder; property Color default clWhite; property Ctl3D; property Font; property TabOrder; property TabStop; property ShowAddress: Boolean read FShowAddress write SetShowAddress default True; property ShowCharacters: Boolean read FShowCharacters write SetShowCharacters default True; property AddressColor: TColor index 0 read GetFileColor write SetFileColor default clBlack; property HexDataColor: TColor index 1 read GetFileColor write SetFileColor default clBlack; property AnsiCharColor: TColor index 2 read GetFileColor write SetFileColor default clBlack; end;

function CreateHexDump(AOwner: TWinControl): THexDump;

implementation

{ Form Methods }

function CreateHexDump(AOwner: TWinControl): THexDump; begin Result := THexDump.Create(AOwner); with Result do begin Parent := AOwner; Font.Name := 'FixedSys'; ShowCharacters := True; Align := alClient; end; end;

{ THexDump }

constructor THexDump.Create(AOwner: TComponent); begin inherited Create(AOwner); ControlStyle := [csFramed]; FBorder := bsSingle; Color := clWhite; FShowAddress := True; FShowCharacters := True; Width := 300; Height := 200; FillChar(FHexData, SizeOf(FHexData), #9); end;

destructor THexDump.Destroy; begin inherited Destroy; end;

procedure THexDump.CheckActive; begin if not FActive then raise Exception.Create('Operation not allowed unless viewing data'); end;

procedure THexDump.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); with Params do begin if FBorder = bsSingle then Style := Style or WS_BORDER; Style := Style or WS_VSCROLL; end; end;

{ VCL Command Messages }

procedure THexDump.CMFontChanged(var Message: TMessage); begin inherited; Canvas.Font := Self.Font; FItemHeight := Canvas.TextHeight('A') + 2; FItemWidth := Canvas.TextWidth('D') + 1; CalcPaintParams; AdjustScrollBars; end;

procedure THexDump.CMEnter; begin inherited; { InvalidateLineMarker; } end;

procedure THexDump.CMExit; begin inherited; { InvalidateLineMarker; } end;

{ Windows Messages }

procedure THexDump.WMSize(var Message: TWMSize); begin inherited; CalcPaintParams; AdjustScrollBars; end;

procedure THexDump.WMGetDlgCode(var Message: TWMGetDlgCode); begin Message.Result := DLGC_WANTARROWS; end;

procedure THexDump.WMVScroll(var Message: TWMVScroll); var NewTopLine: Integer; LinesMoved: Integer; R: TRect; begin inherited; NewTopLine := FTopLine; case Message.ScrollCode of SB_LINEDOWN: Inc(NewTopLine); SB_LINEUP: Dec(NewTopLine); SB_PAGEDOWN: Inc(NewTopLine, FVisibleLines - 1); SB_PAGEUP: Dec(NewTopLine, FVisibleLines - 1); SB_THUMBPOSITION, SB_THUMBTRACK: NewTopLine := Message.Pos; end;

if NewTopLine < 0 then NewTopLine := 0; if NewTopLine >= FLineCount then NewTopLine := FLineCount - 1;

if NewTopLine <> FTopLine then begin LinesMoved := FTopLine - NewTopLine; FTopLine := NewTopLine; SetScrollPos(Handle, SB_VERT, FTopLine, True);

if Abs(LinesMoved) = 1 then begin R := Bounds(0, 0, ClientWidth, ClientHeight - FItemHeight); if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);

ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);

if LinesMoved = -1 then begin R.Top := ClientHeight - FItemHeight; R.Bottom := ClientHeight; end else begin R.Top := 0; R.Bottom := FItemHeight; end;

Windows.InvalidateRect(Handle, @R, False);

end else Invalidate; end; end;

{ Painting Related }

procedure THexDump.CalcPaintParams; const Divisor: array[boolean] of Integer = (3,4); var CharsPerLine: Integer;

begin if FItemHeight < 1 then Exit; FVisibleLines := (ClientHeight div FItemHeight) + 1; CharsPerLine := ClientWidth div FItemWidth; if FShowAddress then Dec(CharsPerLine, 10); FBytesPerLine := CharsPerLine div Divisor[FShowCharacters]; if FBytesPerLine < 1 then FBytesPerLine := 1 else if FBytesPerLine > MAXDIGITS then FBytesPerLine := MAXDIGITS; FLineCount := (DataSize div FBytesPerLine); if Boolean(DataSize mod FBytesPerLine) then Inc(FLineCount); end;

procedure THexDump.InvalidateLine(Index: Integer); var R: TRect; begin if (Index >= FTopLine) and (Index <= FTopLine + FVisibleLines - 1) then begin R := Rect(0, 0, ClientWidth, FItemHeight); OffsetRect(R, 0, (Index - FTopLine) * FItemHeight); Windows.InvalidateRect(Handle, @R, False); end; end;

procedure THexDump.AdjustScrollBars; begin SetScrollRange(Handle, SB_VERT, 0, FLineCount - 1, True); end;

function THexDump.ScrollIntoView: Boolean; begin Result := False; if FCurrentLine < FTopLine then begin Result := True; SetTopLine(FCurrentLine); end else if FCurrentLine >= (FTopLine + FVisibleLines) - 1 then begin SetTopLine(FCurrentLine - (FVisibleLines - 2)); Result := True; end; end;

procedure THexDump.SetTopLine(Value: Integer); var LinesMoved: Integer; R: TRect; begin if Value <> FTopLine then begin if Value < 0 then Value := 0; if Value >= FLineCount then Value := FLineCount - 1;

LinesMoved := FTopLine - Value; FTopLine := Value; SetScrollPos(Handle, SB_VERT, FTopLine, True);

if Abs(LinesMoved) = 1 then begin R := Bounds(1, 0, ClientWidth, ClientHeight - FItemHeight); if LinesMoved = 1 then OffsetRect(R, 0, FItemHeight);

ScrollWindow(Handle, 0, FItemHeight * LinesMoved, @R, nil);

if LinesMoved = -1 then begin R.Top := ClientHeight - FItemHeight; R.Bottom := ClientHeight; end else begin R.Top := 0; R.Bottom := FItemHeight; end;

InvalidateRect(Handle, @R, False);

end else Invalidate; end; end;

procedure THexDump.SetCurrentLine(Value: Integer); var R: TRect; begin if Value <> FCurrentLine then begin if Value < 0 then Value := 0; if Value >= FLineCount then Value := FLineCount - 1;

if (FCurrentLine >= FTopLine) and (FCurrentLine < FTopLine + FVisibleLines - 1) then begin R := Bounds(0, 0, 1, FItemHeight); OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight); Windows.InvalidateRect(Handle, @R, True); end; FCurrentLine := Value;

R := Bounds(0, 0, 1, FItemHeight); OffsetRect(R, 0, (FCurrentLine - FTopLine) * FItemHeight); Windows.InvalidateRect(Handle, @R, True); ScrollIntoView; end; end;

procedure THexDump.Paint; var R: TRect; I: Integer; AddressWidth: Integer; TabStop: Integer; ByteCnt: Integer; begin inherited Paint; Canvas.Brush.Color := Self.Color; if FShowAddress then AddressWidth := FItemWidth*10 else AddressWidth := 0; R := Bounds(1, 0, ClientWidth, FItemHeight); TabStop := FItemWidth*3; Canvas.Font.Color := FFileColors[1]; ByteCnt := FBytesPerLine; for I := 0 to FVisibleLines - 1 do begin R.Left := 1; if I + FTopLine < FLineCount then begin if FShowAddress then begin Canvas.Font.Color := FFileColors[0]; R.Right := R.Left + AddressWidth; ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineAddr(I+FTopLine), 9, nil); R.Left := R.Right; R.Right := ClientWidth; Canvas.Font.Color := FFileColors[1]; end; if (I+FTopLine = FLineCount-1) and ((DataSize mod FBytesPerLine) > 0) then ByteCnt := DataSize mod FBytesPerLine; TabbedTextOut(Canvas.Handle, R.Left, R.Top, LineData(I+FTopLine), (ByteCnt*3)-1, 1, TabStop, R.Left); if FShowCharacters then begin R.Left := AddressWidth+(FItemWidth*(FBytesPerLine*3)); Canvas.Font.Color := FFileColors[2]; ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, LineChars(I+FTopLine), ByteCnt, nil); end; end else ExtTextOut(Canvas.Handle, R.Left, R.Top, ETO_OPAQUE or ETO_CLIPPED, @R, nil, 0, nil); OffsetRect(R, 0, FItemHeight); end; end;

{ Event Overrides }

procedure THexDump.KeyDown(var Key: Word; Shift: TShiftState); begin inherited KeyDown(Key, Shift); if not FActive then Exit;

case Key of VK_DOWN: CurrentLine := CurrentLine + 1; VK_UP: CurrentLine := CurrentLine - 1; VK_NEXT: CurrentLine := CurrentLine + FVisibleLines; VK_PRIOR: CurrentLine := CurrentLine - FVisibleLines; VK_HOME: CurrentLine := 0; VK_END: CurrentLine := FLineCount - 1; end; end;

procedure THexDump.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseDown(Button, Shift, X, Y); if not Focused then SetFocus; if (Button = mbLeft) and FActive then CurrentLine := FTopLine + (Y div FItemHeight); end;

{ Property Set/Get Routines }

procedure THexDump.SetBorder(Value: TBorderStyle); begin if Value <> FBorder then begin FBorder := Value; RecreateWnd; end; end;

procedure THexDump.SetShowAddress(Value: Boolean); begin if FShowAddress <> Value then begin FShowAddress := Value; Invalidate; end; end;

procedure THexDump.SetShowCharacters(Value: Boolean); begin if Value <> FShowCharacters then begin FShowCharacters := Value; Invalidate; end; end;

procedure THexDump.SetFileColor(Index: Integer; Value: TColor); begin if FFileColors[Index] <> Value then begin FFileColors[Index] := Value; Invalidate; end; end;

function THexDump.GetFileColor(Index: Integer): TColor; begin Result := FFileColors[Index]; end;

procedure THexDump.SetAddress(Value: Pointer); begin FActive := Value <> nil; FAddress := Value; Invalidate; end;

procedure THexDump.SetDataSize(Value: Integer); begin FDataSize := Value; CalcPaintParams; Invalidate; AdjustScrollBars; end;

function THexDump.LineAddr(Index: Integer): PChar; begin Result := StrFmt(FLineAddr, '%p:', [Pointer(PChar(Address)+Index*FBytesPerLine)]); end;

function THexDump.LineData(Index: Integer): PChar;

procedure SetData(P: PChar); const HexDigits : array[0..15] of Char = '0123456789ABCDEF'; var I: Integer; B: Byte; begin for I := 0 to FBytesPerLine-1 do begin try B := Byte(P[I]); FHexData[I][0] := HexDigits[B SHR $04]; FHexData[I][1] := HexDigits[B AND $0F]; except FHexData[I][0] := '?'; FHexData[I][1] := '?'; end;

end; end;

begin SetData(PChar(FAddress) + Index*FBytesPerLine); Result := FHexData[0]; end;

function THexDump.LineChars(Index: Integer): PChar; begin Result := PChar(FAddress) + Index*FBytesPerLine; end;

end.

Rxmain.pas 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 SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, ExeImage, StdCtrls, Buttons, ExtCtrls, ComCtrls, Menus, RXMisc, HexDump;

type TMainForm = class(TForm) StatusBar: TStatusBar; TreeViewPanel: TPanel; Panel1: TPanel; ImageViewer: TImage; ListView: TListView; TreeView: TTreeView; Splitter: TPanel; Notebook: TNotebook; ListViewPanel: TPanel; ListViewCaption: TPanel; FileOpenDialog: TOpenDialog; FileSaveDialog: TSaveDialog; MainMenu: TMainMenu; miFile: TMenuItem; miFileExit: TMenuItem; miFileSave: TMenuItem; miFileOpen: TMenuItem; miView: TMenuItem; miViewStatusBar: TMenuItem; miViewLargeIcons: TMenuItem; miViewSmallIcons: TMenuItem; miViewList: TMenuItem; miViewDetails: TMenuItem; miHelp: TMenuItem; miHelpAbout: TMenuItem; Small: TImageList; Large: TImageList; StringViewer: TMemo; 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); private FExeFile: TExeImage; HexDump: THexDump; SplitControl: TSplitControl; procedure LoadResources(ResList: TResourceList; Node: TTreeNode); procedure DisplayResources; procedure UpdateViewPanel; procedure UpdateListView(ResList: TResourceList); procedure UpdateStatusLine(ResItem: TResourceItem); end;

var MainForm: TMainForm;

implementation

uses About, RXTypes;

{$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'; SNoResSelected = 'No resource selected'; SFormCaption = 'Resource Explorer'; 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) = idYes; end;

{ Non Event Handlers }

procedure TMainForm.LoadResources(ResList: TResourceList; Node: TTreeNode); var I: Integer; CNode: TTreeNode; begin 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); Caption := Format('%s - %s', [SFormCaption, LowerCase(FExeFile.FileName)]); with TreeView do begin SetFocus; Selected := Items[0]; end; end;

procedure TMainForm.UpdateViewPanel; var R: TResourceItem; 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, rtIconEntry, rtCursorEntry: begin ImageViewer.Picture.Assign(R); Notebook.PageIndex := 1; end; rtString, rtMenu: begin StringViewer.Lines.Assign(R); StringViewer.SelStart := 0; Notebook.PageIndex := 2; end else begin HexDump.Address := R.RawData; HexDump.DataSize := R.Size; Notebook.PageIndex := 3; 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 }

procedure TMainForm.FormCreate(Sender: TObject); 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 := 0; if (ParamCount > 0) and FileExists(ParamStr(1)) then begin Show; FExeFile := TExeImage.Create(Self, ParamStr(1)); DisplayResources; end; end;

{ Menu Event Handlers }

procedure TMainForm.FileOpen(Sender: TObject); var TmpExeFile: TExeImage; begin with FileOpenDialog do begin if not Execute then Exit; TmpExeFile := TExeImage.Create(Self, FileName); if Assigned(FExeFile) then FExeFile.Destroy; FExeFile := TmpExeFile; DisplayResources; end; 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]; 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 About.ShowAboutBox; end;

procedure TMainForm.ToggleStatusBar(Sender: TObject); begin StatusBar.Visible := not StatusBar.Visible; end;

procedure TMainForm.TreeViewChange(Sender: TObject; Node: TTreeNode); begin UpdateViewPanel; 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;

end.

Rxmisc.pas unit RXMisc;

interface

uses Windows, Forms, Controls;

type TSplitControl = class private FForm: TForm; FSplitControl, FSizeTarget: TControl; FVertical: Boolean; FSplit: TPoint; function GetSizing: Boolean; procedure DrawSizingLine; public constructor Create(AForm: TForm); procedure BeginSizing(ASplitControl, ATargetControl: TControl); procedure ChangeSizing(X, Y: Integer); procedure EndSizing; property Sizing: Boolean read GetSizing; end;

implementation

uses SysUtils, Classes;

function CToC(C1, C2: TControl; P: TPoint): TPoint; begin Result := C1.ScreenToClient(C2.ClientToScreen(P)); end;

{ TSplitControl }

constructor TSplitControl.Create(AForm: TForm); begin FForm := AForm; end;

function TSplitControl.GetSizing: Boolean; begin Result := FSplitControl <> nil; end;

procedure TSplitControl.DrawSizingLine; var P: TPoint; begin P := CToC(FForm, FSplitControl, FSplit); with FForm.Canvas do begin MoveTo(P.X, P.Y); if FVertical then LineTo(CToC(FForm, FSplitControl, Point(FSplitControl.Width, 0)).X, P.Y) else LineTo(P.X, CToC(FForm, FSplitControl, Point(0, FSplitControl.Height)).Y) end; end;

procedure TSplitControl.BeginSizing(ASplitControl, ATargetControl: TControl); begin FSplitControl := ASplitControl; FSizeTarget := ATargetControl; SetCaptureControl(FSplitControl); FVertical := ASplitControl.Width > ASplitControl.Height; if FVertical then FSplit := Point(0, ASplitControl.Top) else FSplit := Point(ASplitControl.Left, 0); FForm.Canvas.Handle := GetDCEx(FForm.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS or DCX_LOCKWINDOWUPDATE); with FForm.Canvas do begin Pen.Color := clWhite; if FVertical then Pen.Width := ASplitControl.Height else Pen.Width := ASplitControl.Width; Pen.Mode := pmXOR; end; DrawSizingLine; end;

procedure TSplitControl.ChangeSizing(X, Y: Integer); begin DrawSizingLine; if FVertical then FSplit.Y := Y else FSplit.X := X; DrawSizingLine; end;

procedure TSplitControl.EndSizing; var DC: HDC; P: TPoint; begin DrawSizingLine; P := CToC(FSizeTarget, FSplitControl, FSplit); SetCaptureControl(nil); FSplitControl := nil; with FForm do begin DC := Canvas.Handle; Canvas.Handle := 0; ReleaseDC(Handle, DC); end; if FVertical then FSizeTarget.Height := P.Y else FSizeTarget.Width := P.X; end;

end.

Rxtypes.pas unit rxtypes;

interface

uses Windows;

const IMAGE_DOS_SIGNATURE = $5A4D; { MZ } IMAGE_OS2_SIGNATURE = $454E; { NE } IMAGE_OS2_SIGNATURE_LE = $454C; { LE } IMAGE_VXD_SIGNATURE = $454C; { LE } IMAGE_NT_SIGNATURE = $00004550; { PE00 }

IMAGE_SIZEOF_SHORT_NAME = 8; IMAGE_SIZEOF_SECTION_HEADER = 40; IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; IMAGE_RESOURCE_NAME_IS_STRING = $80000000; IMAGE_RESOURCE_DATA_IS_DIRECTORY = $80000000; IMAGE_OFFSET_STRIP_HIGH = $7FFFFFFF;

type PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER; IMAGE_DOS_HEADER = packed record { DOS .EXE header } e_magic : WORD; { Magic number } e_cblp : WORD; { Bytes on last page of file } e_cp : WORD; { Pages in file } e_crlc : WORD; { Relocations } e_cparhdr : WORD; { Size of header in paragraphs } e_minalloc : WORD; { Minimum extra paragraphs needed } e_maxalloc : WORD; { Maximum extra paragraphs needed } e_ss : WORD; { Initial (relative) SS value } e_sp : WORD; { Initial SP value } e_csum : WORD; { Checksum } e_ip : WORD; { Initial IP value } e_cs : WORD; { Initial (relative) CS value } e_lfarlc : WORD; { File address of relocation table } e_ovno : WORD; { Overlay number } e_res : packed array [0..3] of WORD; { Reserved words } e_oemid : WORD; { OEM identifier (for e_oeminfo) } e_oeminfo : WORD; { OEM information; e_oemid specific } e_res2 : packed array [0..9] of WORD; { Reserved words } e_lfanew : Longint; { File address of new exe header } end;

PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER; IMAGE_FILE_HEADER = packed record Machine : WORD; NumberOfSections : WORD; TimeDateStamp : DWORD; PointerToSymbolTable : DWORD; NumberOfSymbols : DWORD; SizeOfOptionalHeader : WORD; Characteristics : WORD; end;

PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY; IMAGE_DATA_DIRECTORY = packed record VirtualAddress : DWORD; Size : DWORD; end;

PIMAGE_OPTIONAL_HEADER = ^IMAGE_OPTIONAL_HEADER; IMAGE_OPTIONAL_HEADER = packed record { Standard fields. } Magic : WORD; MajorLinkerVersion : Byte; MinorLinkerVersion : Byte; SizeOfCode : DWORD; SizeOfInitializedData : DWORD; SizeOfUninitializedData : DWORD; AddressOfEntryPoint : DWORD; BaseOfCode : DWORD; BaseOfData : DWORD; { NT additional fields. } ImageBase : DWORD; SectionAlignment : DWORD; FileAlignment : DWORD; MajorOperatingSystemVersion : WORD; MinorOperatingSystemVersion : WORD; MajorImageVersion : WORD; MinorImageVersion : WORD; MajorSubsystemVersion : WORD; MinorSubsystemVersion : WORD; Reserved1 : DWORD; SizeOfImage : DWORD; SizeOfHeaders : DWORD; CheckSum : DWORD; Subsystem : WORD; DllCharacteristics : WORD; SizeOfStackReserve : DWORD; SizeOfStackCommit : DWORD; SizeOfHeapReserve : DWORD; SizeOfHeapCommit : DWORD; LoaderFlags : DWORD; NumberOfRvaAndSizes : DWORD; DataDirectory : packed array [0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of IMAGE_DATA_DIRECTORY; end;

PIMAGE_SECTION_HEADER = ^IMAGE_SECTION_HEADER; IMAGE_SECTION_HEADER = packed record Name : packed array [0..IMAGE_SIZEOF_SHORT_NAME-1] of Char; PhysicalAddress : DWORD; // or VirtualSize (union); VirtualAddress : DWORD; SizeOfRawData : DWORD; PointerToRawData : DWORD; PointerToRelocations : DWORD; PointerToLinenumbers : DWORD; NumberOfRelocations : WORD; NumberOfLinenumbers : WORD; Characteristics : DWORD; end;

PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS; IMAGE_NT_HEADERS = packed record Signature : DWORD; FileHeader : IMAGE_FILE_HEADER; OptionalHeader : IMAGE_OPTIONAL_HEADER; end;

{ Resources }

PIMAGE_RESOURCE_DIRECTORY = ^IMAGE_RESOURCE_DIRECTORY; IMAGE_RESOURCE_DIRECTORY = packed record Characteristics : DWORD; TimeDateStamp : DWORD; MajorVersion : WORD; MinorVersion : WORD; NumberOfNamedEntries : WORD; NumberOfIdEntries : WORD; end;

PIMAGE_RESOURCE_DIRECTORY_ENTRY = ^IMAGE_RESOURCE_DIRECTORY_ENTRY; IMAGE_RESOURCE_DIRECTORY_ENTRY = packed record Name: DWORD; // Or ID: Word (Union) OffsetToData: DWORD; end;

PIMAGE_RESOURCE_DATA_ENTRY = ^IMAGE_RESOURCE_DATA_ENTRY; IMAGE_RESOURCE_DATA_ENTRY = packed record OffsetToData : DWORD; Size : DWORD; CodePage : DWORD; Reserved : DWORD; end;

PIMAGE_RESOURCE_DIR_STRING_U = ^IMAGE_RESOURCE_DIR_STRING_U; IMAGE_RESOURCE_DIR_STRING_U = packed record Length : WORD; NameString : array [0..0] of WCHAR; end;

{ /* Predefined resource types */ #define RT_NEWRESOURCE 0x2000 #define RT_ERROR 0x7fff #define RT_CURSOR 1 #define RT_BITMAP 2 #define RT_ICON 3 #define RT_MENU 4 #define RT_DIALOG 5 #define RT_STRING 6 #define RT_FONTDIR 7 #define RT_FONT 8 #define RT_ACCELERATORS 9 #define RT_RCDATA 10 #define RT_MESSAGETABLE 11 #define RT_GROUP_CURSOR 12 #define RT_GROUP_ICON 14 #define RT_VERSION 16 #define RT_NEWBITMAP (RT_BITMAP|RT_NEWRESOURCE) #define RT_NEWMENU (RT_MENU|RT_NEWRESOURCE) #define RT_NEWDIALOG (RT_DIALOG|RT_NEWRESOURCE)

}

type TResourceType = ( rtUnknown0, rtCursorEntry, rtBitmap, rtIconEntry, rtMenu, rtDialog, rtString, rtFontDir, rtFont, rtAccelerators, rtRCData, rtMessageTable, rtCursor, rtUnknown13, rtIcon, rtUnknown15, rtVersion);

{ Resource Type Constants }

const StringsPerBlock = 16;

{ Resource Related Structures from RESFMT.TXT in WIN32 SDK }

type

PIconHeader = ^TIconHeader; TIconHeader = packed record wReserved: Word; { Currently zero } wType: Word; { 1 for icons } wCount: Word; { Number of components } end;

PIconResInfo = ^TIconResInfo; TIconResInfo = packed record bWidth: Byte; bHeight: Byte; bColorCount: Byte; bReserved: Byte; wPlanes: Word; wBitCount: Word; lBytesInRes: DWORD; wNameOrdinal: Word; { Points to component } end;

PCursorResInfo = ^TCursorResInfo; TCursorResInfo = packed record wWidth: Word; wHeight: Word; wPlanes: Word; wBitCount: Word; lBytesInRes: DWORD; wNameOrdinal: Word; { Points to component } end;

implementation

end.

Or... we could have a clear overview of the program's underlying object structure in 3 easy steps using With Class 3.1!

#1: In With Class, we set our preference to Delphi.

#2: Now we use With Class's utility to reverse entire directory of the project.

#3: Then we choose we aspects of the program's structure we would like to illustrate...

And in just seconds, we have a clear picture of the whole program's structure! (represented here in UML format).


As you can see, each class with it's methods, properties, has been clearly laid out - along with it's relationships to all of the other classes defined in the program! Now, you can interact with this diagram, changes relations, structure, and code; or simply use the diagram for documentation purposes. And when you're done, you can use With Class's powerful scripting language to generate new code from the changes you've made!


cialis link tw886to generic cialis prices best price viagra cialis cialis attorney cincinnati cialis lowest price generic cialis trial packs black buy casino cialis diet followup gambling health jack phentermine poker post viagra cialis and bodybuilding cialis medication free generic cialis samples black buy casino cialis diet followup gambling jack online order phentermine poker post viagra cialis black box cialis message boards generic cialis american express apotheke cialis cialis and levitra and viagra and generic cialis muscle ache generic cialis hong kong archive blog cialis inurl cialis and levitra cialis line mexico does cialis work for women allowed black buy casino cialis diet holdem jack online order phentermine poker tag texas viagra xhtml cialis and multiple coitus cialis no prescription generic cialis price best for premature ejaculation viagra cialis levitra cialis and women cialis link liracrogreekbostoncom generic cialis allowed casino cialis diet phentermine poker tag viagra xhtml cialis add url cialis lawyer ohio experience cialis without ed allowed cialis phentermine tag viagra xhtml cialis back pain cialis online order how to get free cialis sample black buy casino cialis diet gambling jack order phentermine poker tag viagra xhtml cialis discount cialis maximum dose international order for generic cialis blogid buy casino cialis generic inurl order phentermine poker viagra cialis and blood pressure cialis mexico is cialis for me blogid buy casino cialis inurl phentermine poker viagra cialis and grapefruit cialis levitra viagra discount cialis best buy cialis generic ciales rock climbing cialis international shipping does cialis or levitra work best for diabetics allowed black buy casino cialis diet health jack phentermine poker sex tag title viagra xhtml cheap viagra cialis cialis lawyer cincinnati effectiveness of cialis reported allowed black casino cialis diet gambling jack phentermine poker tag viagra xhtml cheapest and cialis and generic and lowest price cialis injury attorney ohio compare levitra and cialis add cialis link suggest catholic cult and cialis cialis lcos lily online free cialis approval cialis fda cialis and early ejaculation cialis levitra viagra interaction generic cialis cheap free shipping free consultation articles on cialis cheapest cialis cialis injury lawyer columbus generic cialis international shipping buy cheapest cialis cialis compare levitra viagra cialis line prescription generic cialis next day black buy casino cheap cialis diet followup gambling health jack online order phentermine poker post viagra ciales cialis international shipping contact number cialis add buy cialis url cialis 20mg tablet cialis liquid how long does cialis take to work black buy casino cialis diet gambling health jack phentermine poker tag viagra xhtml cialis and alcohol cialis lawyer cleveland effectiveness viagra cialis levitra allowed casino cialis phentermine tag viagra xhtml cheapest cialis free samples cialis levitra versus versus viagra fda pharmaceutical testing trials cialis anti cialis impotence cheapest cialis price cialis injury attorney columbus compare viagra cialis and levitra add cialis site cheapest cialis with no perscription cialis injury lawyer cleveland compare viagra to cialis achat ligne cialis cheap cialis link suggest cialis impotence drug cialis with no prescription add buy cialis site canada cialis online cialis information prescribing cialis viagra taken together where can i buy cialis online black buy casino cialis diet followup gambling jack order phentermine poker post viagra cialis blindness cialis link suggest diabeties viagra cialis levitra allowed black buy casino cialis diet gambling jack order phentermine poker tag viagra xhtml cheap cialis online cialis generic tadalafil cialis without prescriptions add cialis generic link cialis and levitra taken together cialis information clinical trial testing cialis for high blood preasure add cialis link online canada generic cialis cialis germany cialis strength time line to buy without prescription cialis or levitra in detrit area buy cialis submit=buy cialis cialis drug interaction cialis online liquid cialis black buy casino cialis diet followup gambling jack low online order phentermine poker viagra cialis attorney cleveland cialis injury lawyer cincinnati cialis vs viagra .. can you take cialis with viagra cialis home page cialis western open ticket add buy cialis link canada cialis generic cialis generic online cialis uprima viagra value pharmaceuticals cialis buy cialis order cialis eli lilly cialis pharmacy natural supplement like cialis