Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. {$mode delphi}
  2.  
  3. unit ExeImage;
  4.  
  5. interface
  6.  
  7. uses
  8.   TypInfo, Classes, SysUtils, Windows, RXTypes;
  9.  
  10. const
  11.   MF_END = $80;
  12.  
  13. type
  14.  
  15. { Exceptions }
  16.  
  17.   EExeError = class(Exception);
  18.   ENotImplemented = class(Exception)
  19.   public
  20.     constructor Create();
  21.   end;
  22.  
  23. { Forward Declarations }
  24.  
  25.   TResourceItem = class;
  26.   TResourceClass = class of TResourceItem;
  27.   TResourceList = class;
  28.  
  29. { TExeImage }
  30.  
  31.   TExeImage = class(TComponent)
  32.   private
  33.     FFileName: string;
  34.     FFileHandle: THandle;
  35.     FFileMapping: THandle;
  36.     FFileBase: Pointer;
  37.     FDosHeader: PIMAGE_DOS_HEADER;
  38.     FNTHeader: PIMAGE_NT_HEADERS;
  39.     FResourceList: TResourceList;
  40.     FIconResources: TResourceItem;
  41.     FCursorResources: TResourceItem;
  42.     FResourceBase: Longint;
  43.     FResourceRVA: Longint;
  44.     function GetResourceList: TResourceList;
  45.     function GetSectionHdr(const SectionName: string;
  46.       var Header: PIMAGE_SECTION_HEADER): Boolean;
  47.   public
  48.     constructor CreateImage(AOwner: TComponent; const AFileName: string);
  49.     destructor Destroy; override;
  50.     property FileName: string read FFileName;
  51.     property Resources: TResourceList read GetResourceList;
  52.   end;
  53.  
  54. { TResourceItem }
  55.  
  56.   TResourceItem = class(TComponent)
  57.   private
  58.     FList: TResourceList;
  59.     FDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY;
  60.     function DataEntry: PIMAGE_RESOURCE_DATA_ENTRY;
  61.     function FExeImage: TExeImage;
  62.     function FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY;
  63.     function GetResourceItem(Index: Integer): TResourceItem;
  64.     function GetResourceType: TResourceType;
  65.   protected
  66.     function GetName: string; virtual;
  67.     function GetResourceList: TResourceList; virtual;
  68.   public
  69.     constructor CreateItem(AOwner: TComponent; ADirEntry: Pointer);
  70.     function IsList: Boolean; virtual;
  71.     function Offset: Integer;
  72.     function Size: Integer;
  73.     function RawData: Pointer;
  74.     function ResTypeStr: string;
  75.     procedure SaveToFile(const FileName: string);
  76.     procedure SaveToStream(Stream: TStream); virtual;
  77.     property Items[Index: Integer]: TResourceItem read GetResourceItem; default;
  78.     property List: TResourceList read GetResourceList;
  79.     property Name: string read GetName;
  80.     property ResType: TResourceType read GetResourceType;
  81.   end;
  82.  
  83. { TIconResource }
  84.  
  85.   TIconResource = class(TResourceItem)
  86.   protected
  87.     function GetResourceList: TResourceList; override;
  88.   public
  89.     function IsList: Boolean; override;
  90.   end;
  91.  
  92. { TIconResEntry }
  93.  
  94.   TIconResEntry = class(TResourceItem)
  95.   protected
  96.     FResInfo: PIconResInfo;
  97.     function GetName: string; override;
  98.     procedure AssignTo(Dest: TPersistent); override;
  99.   public
  100.     procedure SaveToStream(Stream: TStream); override;
  101.   end;
  102.  
  103. { TCursorResource }
  104.  
  105.   TCursorResource = class(TIconResource)
  106.   protected
  107.     function GetResourceList: TResourceList; override;
  108.   end;
  109.  
  110. { TCursorResEntry }
  111.  
  112.   TCursorResEntry = class(TIconResEntry)
  113.   protected
  114.     FResInfo: PCursorResInfo;
  115.     function GetName: string; override;
  116.   end;
  117.  
  118. { TBitmapResource }
  119.  
  120.   TBitmapResource = class(TResourceItem)
  121.   protected
  122.     procedure AssignTo(Dest: TPersistent); override;
  123.   public
  124.     procedure SaveToStream(Stream: TStream); override;
  125.   end;
  126.  
  127. { TStringResource }
  128.  
  129.   TStringResource = class(TResourceItem)
  130.   protected
  131.     procedure AssignTo(Dest: TPersistent); override;
  132.   end;
  133.  
  134. { TMenuResource }
  135.  
  136.   TMenuResource = class(TResourceItem)
  137.   private
  138.     FNestStr: string;
  139.     FNestLevel: Integer;
  140.     procedure SetNestLevel(Value: Integer);
  141.   protected
  142.     procedure AssignTo(Dest: TPersistent); override;
  143.     property NestLevel: Integer read FNestLevel write SetNestLevel;
  144.     property NestStr: string read FNestStr;
  145.   end;
  146.  
  147. { TResourceList }
  148.  
  149.   TResourceList = class(TComponent)
  150.   protected
  151.     FList: TList;
  152.     FResDir: PIMAGE_RESOURCE_DIRECTORY;
  153.     FExeImage: TExeImage;
  154.     FResType: Integer;
  155.     function List: TList; virtual;
  156.     function GetResourceItem(Index: Integer): TResourceItem;
  157.   public
  158.     constructor CreateList(AOwner: TComponent; ResDirOfs: Longint;
  159.       AExeImage: TExeImage);
  160.     destructor Destroy; override;
  161.     function Count: Integer;
  162.     property Items[Index: Integer]: TResourceItem read GetResourceItem; default;
  163.   end;
  164.  
  165. { TIconResourceList }
  166.  
  167.   TIconResourceList = class(TResourceList)
  168.   protected
  169.     function List: TList; override;
  170.   end;
  171.  
  172. { TCursorResourceList }
  173.  
  174.   TCursorResourceList = class(TResourceList)
  175.   protected
  176.     function List: TList; override;
  177.   end;
  178.  
  179. implementation
  180.  
  181. constructor ENotImplemented.Create();
  182. begin
  183.   inherited Create('Not Implemented');
  184. end;
  185.  
  186.  
  187. { This function maps a resource type to the associated resource class }
  188.  
  189. function GetResourceClass(ResType: Integer): TResourceClass;
  190. const
  191.   TResourceClasses: array[TResourceType] of TResourceClass = (
  192.     TResourceItem,      { rtUnknown0 }
  193.     TCursorResEntry,    { rtCursorEntry }
  194.     TBitmapResource,    { rtBitmap }
  195.     TIconResEntry,      { rtIconEntry }
  196.     TMenuResource,      { rtMenu }
  197.     TResourceItem,      { rtDialog }
  198.     TStringResource,    { rtString }
  199.     TResourceItem,      { rtFontDir }
  200.     TResourceItem,      { rtFont }
  201.     TResourceItem,      { rtAccelerators }
  202.     TResourceItem,      { rtRCData }
  203.     TResourceItem,      { rtMessageTable }
  204.     TCursorResource,    { rtGroupCursor }
  205.     TResourceItem,      { rtUnknown13 }
  206.     TIconResource,      { rtIcon }
  207.     TResourceItem,      { rtUnknown15 }
  208.     TResourceItem);     { rtVersion }
  209. begin
  210.   if (ResType >= Integer(Low(TResourceType))) and
  211.     (ResType <= Integer(High(TResourceType))) then
  212.     Result := TResourceClasses[TResourceType(ResType)] else
  213.     Result := TResourceItem;
  214. end;
  215.  
  216. { Utility Functions }
  217.  
  218. function Min(A, B: Integer): Integer;
  219. begin
  220.   if A < B then Result := A
  221.   else Result := B;
  222. end;
  223.  
  224. { This function checks if an offset is a string name, or a directory }
  225. {Assumes: IMAGE_RESOURCE_NAME_IS_STRING = IMAGE_RESOURCE_DATA_IS_DIRECTORY}
  226.  
  227. function HighBitSet(L: Longint): Boolean;
  228. begin
  229.   Result := (L and IMAGE_RESOURCE_DATA_IS_DIRECTORY) <> 0;
  230. end;
  231.  
  232. function StripHighBit(L: Longint): Longint;
  233. begin
  234.   Result := L and IMAGE_OFFSET_STRIP_HIGH;
  235. end;
  236.  
  237. function StripHighPtr(L: Longint): Pointer;
  238. begin
  239.   Result := Pointer(L and IMAGE_OFFSET_STRIP_HIGH);
  240. end;
  241.  
  242. { This function converts a pointer to a wide char string into a pascal string }
  243.  
  244. function WideCharToStr(WStr: PWChar; Len: Integer): string;
  245. begin
  246.   if Len = 0 then Len := -1;
  247.   Len := WideCharToMultiByte(CP_ACP, 0, WStr, Len, nil, 0, nil, nil);
  248.   SetLength(Result, Len);
  249.   WideCharToMultiByte(CP_ACP, 0, WStr, Len, PChar(Result), Len, nil, nil);
  250. end;
  251.  
  252. { Exceptions }
  253.  
  254. procedure ExeError(const ErrMsg: string);
  255. begin
  256.   raise EExeError.Create(ErrMsg);
  257. end;
  258.  
  259. { TExeImage }
  260.  
  261. constructor TExeImage.CreateImage(AOwner: TComponent; const AFileName: string);
  262. begin
  263.   inherited Create(AOwner);
  264.   FFileName := AFileName;
  265.   FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ,
  266.     nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  267.   if FFileHandle = INVALID_HANDLE_VALUE then ExeError('Couldn''t open: '+FFileName);
  268.     FFileMapping := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
  269.   if FFileMapping = 0 then ExeError('CreateFileMapping failed');
  270.     FFileBase := MapViewOfFile(FFileMapping, FILE_MAP_READ, 0, 0, 0);
  271.   if FFileBase = nil then ExeError('MapViewOfFile failed');
  272.     FDosHeader := PIMAGE_DOS_HEADER(FFileBase);
  273.   if not FDosHeader.e_magic = IMAGE_DOS_SIGNATURE then
  274.     ExeError('unrecognized file format');
  275.   FNTHeader := PIMAGE_NT_HEADERS(Longint(FDosHeader) + FDosHeader.e_lfanew);
  276.   if IsBadReadPtr(FNTHeader, sizeof(IMAGE_NT_HEADERS)) or
  277.      (FNTHeader.Signature <> IMAGE_NT_SIGNATURE) then
  278.     ExeError('Not a PE (WIN32 Executable) file');
  279.  end;
  280.  
  281. destructor TExeImage.Destroy;
  282. begin
  283.   if FFileHandle <> INVALID_HANDLE_VALUE then
  284.   begin
  285.     UnmapViewOfFile(FFileBase);
  286.     CloseHandle(FFileMapping);
  287.     CloseHandle(FFileHandle);
  288.   end;
  289.   inherited Destroy;
  290. end;
  291.  
  292. function TExeImage.GetSectionHdr(const SectionName: string;
  293.   var Header: PIMAGE_SECTION_HEADER): Boolean;
  294. var
  295.   I: Integer;
  296. begin
  297.   Header := PIMAGE_SECTION_HEADER(FNTHeader);
  298.   Inc(PIMAGE_NT_HEADERS(Header));
  299.   Result := True;
  300.   for I := 0 to FNTHeader.FileHeader.NumberOfSections - 1 do
  301.   begin
  302.     if Strlicomp(Header.Name, PChar(SectionName), IMAGE_SIZEOF_SHORT_NAME) = 0 then Exit;
  303.     Inc(Header);
  304.   end;
  305.   Result := False;
  306. end;
  307.  
  308. function TExeImage.GetResourceList: TResourceList;
  309. var
  310.   ResSectHdr: PIMAGE_SECTION_HEADER;
  311. begin
  312.   if not Assigned(FResourceList) then
  313.   begin
  314.     if GetSectionHdr('.rsrc', ResSectHdr) then
  315.     begin
  316.       FResourceBase := ResSectHdr.PointerToRawData + LongWord(FDosHeader);
  317.       FResourceRVA := ResSectHdr.VirtualAddress;
  318.       FResourceList := TResourceList.CreateList(Self, FResourceBase, Self);
  319.     end
  320.     else
  321.       ExeError('No resources in this file.');
  322.   end;
  323.   Result := FResourceList;
  324. end;
  325.  
  326. { TResourceItem }
  327.  
  328. constructor TResourceItem.CreateItem(AOwner: TComponent; ADirEntry: Pointer);
  329. begin
  330.   inherited Create(AOwner);
  331.   FDirEntry := ADirEntry;
  332. end;
  333.  
  334. function TResourceItem.DataEntry: PIMAGE_RESOURCE_DATA_ENTRY;
  335. begin
  336.   Result := PIMAGE_RESOURCE_DATA_ENTRY(FirstChildDirEntry.OffsetToData
  337.     + Cardinal(FExeImage.FResourceBase));
  338. end;
  339.  
  340. function TResourceItem.FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY;
  341. begin
  342.   Result := PIMAGE_RESOURCE_DIRECTORY_ENTRY(StripHighBit(FDirEntry.OffsetToData) +
  343.     FExeImage.FResourceBase + SizeOf(IMAGE_RESOURCE_DIRECTORY));
  344. end;
  345.  
  346. function TResourceItem.FExeImage: TExeImage;
  347. begin
  348.   Result := (Owner as TResourceList).FExeImage;
  349. end;
  350.  
  351. function TResourceItem.GetResourceItem(Index: Integer): TResourceItem;
  352. begin
  353.   Result := List[Index];
  354. end;
  355.  
  356. function TResourceItem.GetResourceType: TResourceType;
  357. begin
  358.   Result := TResourceType((Owner as TResourceList).FResType);
  359. end;
  360.  
  361. function TResourceItem.IsList: Boolean;
  362. begin
  363.   Result := HighBitSet(FirstChildDirEntry.OffsetToData);
  364. end;
  365.  
  366. function TResourceItem.GetResourceList: TResourceList;
  367. begin
  368.   if not IsList then ExeError('ResourceItem is not a list');
  369.   if not Assigned(FList) then
  370.     FList := TResourceList.CreateList(Self, StripHighBit(FDirEntry.OffsetToData) +
  371.       FExeImage.FResourceBase, FExeImage);
  372.   Result := FList;
  373. end;
  374.  
  375. function TResourceItem.GetName: string;
  376. var
  377.   PDirStr: PIMAGE_RESOURCE_DIR_STRING_U;
  378. begin
  379.   { Check for Level1 entries, these are resource types. }
  380.   if (Owner.Owner = FExeImage) and not HighBitSet(FDirEntry.Name) and
  381.     (FDirEntry.Name <= 16) then
  382.   begin
  383.     Result := Copy(GetEnumName(TypeInfo(TResourceType), FDirEntry.Name), 3, 20);
  384.     Exit;
  385.   end;
  386.  
  387.   if HighBitSet(FDirEntry.Name) then
  388.   begin
  389.     PDirStr := PIMAGE_RESOURCE_DIR_STRING_U(StripHighBit(FDirEntry.Name) +
  390.       FExeImage.FResourceBase);
  391.     Result := WideCharToStr(@PDirStr.NameString, PDirStr.Length);
  392.     Exit;
  393.   end;
  394.   Result := Format('%d', [FDirEntry.Name]);
  395. end;
  396.  
  397. function TResourceItem.Offset: Integer;
  398. begin
  399.   if IsList then
  400.     Result := StripHighBit(FDirEntry.OffsetToData)
  401.   else
  402.     Result := DataEntry.OffsetToData;
  403. end;
  404.  
  405. function TResourceItem.RawData: Pointer;
  406. begin
  407.   with FExeImage do
  408.     Result := pointer(FResourceBase - FResourceRVA + LongInt(DataEntry.OffsetToData));
  409. end;
  410.  
  411. function TResourceItem.ResTypeStr: string;
  412. begin
  413.   Result := Copy(GetEnumName(TypeInfo(TResourceType), Ord(ResType)), 3, 20);
  414. end;
  415.  
  416. procedure TResourceItem.SaveToFile(const FileName: string);
  417. var
  418.   FS: TFileStream;
  419. begin
  420.   FS := TFileStream.Create(FileName, fmCreate);
  421.   try
  422.     Self.SaveToStream(FS);
  423.   finally
  424.     FS.Free;
  425.   end;
  426. end;
  427.  
  428. procedure TResourceItem.SaveToStream(Stream: TStream);
  429. begin
  430.   Stream.Write(RawData^, Size);
  431. end;
  432.  
  433. function TResourceItem.Size: Integer;
  434. begin
  435.   if IsList then
  436.     Result := 0
  437.   else
  438.     Result := DataEntry.Size;
  439. end;
  440.  
  441. { TBitmapResource }
  442.  
  443. procedure TBitmapResource.AssignTo(Dest: TPersistent);
  444. {var
  445.   MemStr: TMemoryStream;
  446.   BitMap: TBitMap;}
  447. begin
  448.   raise ENotImplemented.Create();
  449.  
  450.   {if (Dest is TPicture) then
  451.   begin
  452.     BitMap := TPicture(Dest).Bitmap;
  453.     MemStr := TMemoryStream.Create;
  454.     try
  455.       SaveToStream(MemStr);
  456.       MemStr.Seek(0,0);
  457.       BitMap.LoadFromStream(MemStr);
  458.     finally
  459.       MemStr.Free;
  460.     end
  461.   end
  462.   else
  463.     inherited AssignTo(Dest);}
  464. end;
  465.  
  466. procedure TBitmapResource.SaveToStream(Stream: TStream);
  467.  
  468.   {function GetDInColors(BitCount: Word): Integer;
  469.   begin
  470.     case BitCount of
  471.       1, 4, 8: Result := 1 shl BitCount;
  472.     else
  473.       Result := 0;
  474.     end;
  475.   end;
  476.  
  477. var
  478.   BH: TBitmapFileHeader;
  479.   BI: PBitmapInfoHeader;
  480.   BC: PBitmapCoreHeader;
  481.   ClrUsed: Integer;}
  482. begin
  483.   raise ENotImplemented.Create();
  484.  
  485.   {FillChar(BH, sizeof(BH), #0);
  486.   BH.bfType := $4D42;
  487.   BH.bfSize := Self.Size + sizeof(BH);
  488.   BI := PBitmapInfoHeader(RawData);
  489.   if BI.biSize = sizeof(TBitmapInfoHeader) then
  490.   begin
  491.     ClrUsed := BI.biClrUsed;
  492.     if ClrUsed = 0 then
  493.       ClrUsed := GetDInColors(BI.biBitCount);
  494.     BH.bfOffBits :=  ClrUsed * SizeOf(TRgbQuad) +
  495.       sizeof(TBitmapInfoHeader) + sizeof(BH);
  496.   end
  497.   else
  498.   begin
  499.     BC := PBitmapCoreHeader(RawData);
  500.     ClrUsed := GetDInColors(BC.bcBitCount);
  501.     BH.bfOffBits :=  ClrUsed * SizeOf(TRGBTriple) +
  502.       sizeof(TBitmapCoreHeader) + sizeof(BH);
  503.   end;
  504.   Stream.Write(BH, SizeOf(BH));
  505.   Stream.Write(RawData^, Self.Size);}
  506. end;
  507.  
  508.  
  509. { TIconResource }
  510.  
  511. function TIconResource.GetResourceList: TResourceList;
  512. begin
  513.   if not Assigned(FList) then
  514.     FList := TIconResourceList.CreateList(Owner, LongInt(RawData), FExeImage);
  515.   Result := FList;
  516. end;
  517.  
  518. function TIconResource.IsList: Boolean;
  519. begin
  520.   Result := True;
  521. end;
  522.  
  523. { TIconResEntry }
  524.  
  525. procedure TIconResEntry.AssignTo(Dest: TPersistent);
  526. {var
  527.   hIco: HIcon;}
  528. begin
  529.   raise ENotImplemented.Create();
  530.  
  531.   {if Dest is TPicture then
  532.   begin
  533.     hIco := CreateIconFromResource(RawData, Size, (ResType = rtIconEntry), $30000);
  534.     TPicture(Dest).Icon.Handle := hIco;
  535.   end
  536.   else
  537.     inherited AssignTo(Dest);}
  538. end;
  539.  
  540. function TIconResEntry.GetName: string;
  541. begin
  542.   if Assigned(FResInfo) then
  543.     with FResInfo^ do
  544.       Result := Format('%d X %d %d Colors', [bWidth, bHeight, bColorCount])
  545.   else
  546.     Result := inherited GetName;
  547. end;
  548.  
  549. procedure TIconResEntry.SaveToStream(Stream: TStream);
  550. begin
  551.   raise ENotImplemented.Create();
  552.  
  553.   {with TIcon.Create do
  554.   try
  555.     Handle := CreateIconFromResource(RawData, Self.Size, (ResType <> rtIcon), $30000);
  556.     SaveToStream(Stream);
  557.   finally
  558.     Free;
  559.   end;}
  560. end;
  561.  
  562. { TCursorResource }
  563.  
  564. function TCursorResource.GetResourceList: TResourceList;
  565. begin
  566.   if not Assigned(FList) then
  567.     FList := TCursorResourceList.CreateList(Owner, LongInt(RawData), FExeImage);
  568.   Result := FList;
  569. end;
  570.  
  571. { TCursorResEntry }
  572.  
  573. function TCursorResEntry.GetName: string;
  574. begin
  575.   if Assigned(FResInfo) then
  576.     with FResInfo^ do
  577.       Result := Format('%d X %d %d Bit(s)', [wWidth, wWidth, wBitCount])
  578.   else
  579.     Result := inherited GetName;
  580. end;
  581.  
  582. { TStringResource }
  583.  
  584. procedure TStringResource.AssignTo(Dest: TPersistent);
  585. var
  586.   P: PWChar;
  587.   ID: Integer;
  588.   Cnt: Cardinal;
  589.   Len: Word;
  590. begin
  591.   if (Dest is TStrings) then
  592.     with TStrings(Dest) do
  593.     begin
  594.       BeginUpdate;
  595.       try
  596.         Clear;
  597.         P := RawData;
  598.         Cnt := 0;
  599.         while Cnt < StringsPerBlock do
  600.         begin
  601.           Len := Word(P^);
  602.           if Len > 0 then
  603.           begin
  604.             Inc(P);
  605.             ID := ((FDirEntry.Name - 1) shl 4) + Cnt;
  606.             Add(Format('%d,  "%s"', [ID, WideCharToStr(P, Len)]));
  607.             Inc(P, Len);
  608.           end;
  609.           Inc(Cnt);
  610.         end;
  611.       finally
  612.         EndUpdate;
  613.       end;
  614.     end
  615.   else
  616.     inherited AssignTo(Dest);
  617. end;
  618.  
  619. { TMenuResource }
  620.  
  621. procedure TMenuResource.SetNestLevel(Value: Integer);
  622. begin
  623.   FNestLevel := Value;
  624.   SetLength(FNestStr, Value * 2);
  625.   FillChar(FNestStr[1], Value * 2, ' ');
  626. end;
  627.  
  628. procedure TMenuResource.AssignTo(Dest: TPersistent);
  629. var
  630.   IsPopup: Boolean;
  631.   Len: Word;
  632.   MenuData: PWord;
  633.   MenuEnd: PChar;
  634.   MenuText: PWChar;
  635.   MenuID: Word;
  636.   MenuFlags: Word;
  637.   S: string;
  638. begin
  639.   if (Dest is TStrings) then
  640.     with TStrings(Dest) do
  641.     begin
  642.       BeginUpdate;
  643.       try
  644.         Clear;
  645.         MenuData := RawData;
  646.         MenuEnd := PChar(RawData) + Size;
  647.         Inc(MenuData, 2);
  648.         NestLevel := 0;
  649.         while PChar(MenuData) < MenuEnd do
  650.         begin
  651.           MenuFlags := MenuData^;
  652.           Inc(MenuData);
  653.           IsPopup := (MenuFlags and MF_POPUP) = MF_POPUP;
  654.           MenuID := 0;
  655.           if not IsPopup then
  656.           begin
  657.             MenuID := MenuData^;
  658.             Inc(MenuData);
  659.           end;
  660.           MenuText := PWChar(MenuData);
  661.           Len := lstrlenw(MenuText);
  662.           if Len = 0 then
  663.             S := 'MENUITEM SEPARATOR'
  664.           else
  665.           begin
  666.             S := WideCharToStr(MenuText, Len);
  667.             if IsPopup then
  668.               S := Format('POPUP "%s"', [S]) else
  669.               S := Format('MENUITEM "%s",  %d', [S, MenuID]);
  670.           end;
  671.           Inc(MenuData, Len + 1);
  672.           Add(NestStr + S);
  673.           if (MenuFlags and MF_END) = MF_END then
  674.           begin
  675.             NestLevel := NestLevel - 1;
  676.             Add(NestStr + 'ENDPOPUP');
  677.           end;
  678.           if IsPopup then
  679.             NestLevel := NestLevel + 1;
  680.         end;
  681.       finally
  682.         EndUpdate;
  683.       end;
  684.     end
  685.   else
  686.     inherited AssignTo(Dest);
  687. end;
  688.  
  689. { TResourceList }
  690.  
  691. constructor TResourceList.CreateList(AOwner: TComponent; ResDirOfs: Longint;
  692.   AExeImage: TExeImage);
  693. var
  694.   DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY;
  695. begin
  696.   inherited Create(AOwner);
  697.   FExeImage := AExeImage;
  698.   FResDir := Pointer(ResDirOfs);
  699.   if AOwner <> AExeImage then
  700.     if AOwner.Owner.Owner = AExeImage then
  701.     begin
  702.       DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir);
  703.       inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry));
  704.       FResType := TResourceItem(Owner).FDirEntry.Name;
  705.     end
  706.     else
  707.       FResType := (AOwner.Owner.Owner as TResourceList).FResType;
  708. end;
  709.  
  710. destructor TResourceList.Destroy;
  711. begin
  712.   inherited Destroy;
  713.   FList.Free;
  714. end;
  715.  
  716. function TResourceList.List: TList;
  717. var
  718.   I: Integer;
  719.   DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY;
  720.   DirCnt: Integer;
  721.   ResItem: TResourceItem;
  722. begin
  723.   if not Assigned(FList) then
  724.   begin
  725.     FList := TList.Create;
  726.     DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir);
  727.     inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry));
  728.     DirCnt := FResDir.NumberOfNamedEntries + FResDir.NumberOfIdEntries - 1;
  729.     for I := 0 to DirCnt do
  730.     begin
  731.       { Handle Cursors and Icons specially }
  732.       ResItem := GetResourceClass(FResType).CreateItem(Self, DirEntry);
  733.       if Owner = FExeImage then
  734.         if (TResourceType(DirEntry.Name) in [rtCursorEntry, rtIconEntry]) then
  735.         begin
  736.           if TResourceType(DirEntry.Name) = rtCursorEntry then
  737.             FExeImage.FCursorResources := ResItem else
  738.             FExeImage.FIconResources := ResItem;
  739.           Inc(DirEntry);
  740.           Continue;
  741.         end;
  742.       FList.Add(ResItem);
  743.       Inc(DirEntry);
  744.     end;
  745.   end;
  746.   Result := FList;
  747. end;
  748.  
  749. function TResourceList.Count: Integer;
  750. begin
  751.   Result := List.Count;
  752. end;
  753.  
  754. function TResourceList.GetResourceItem(Index: Integer): TResourceItem;
  755. begin
  756.   Result := List[Index];
  757. end;
  758.  
  759. { TIconResourceList }
  760.  
  761. function TIconResourceList.List: TList;
  762. var
  763.   I,  J, Cnt: Integer;
  764.   ResData: PIconResInfo;
  765.   ResList: TResourceList;
  766.   ResOrd: Cardinal;
  767.   IconResource: TIconResEntry;
  768. begin
  769.   if not Assigned(FList) then
  770.   begin
  771.     FList := TList.Create;
  772.     Cnt := PIconHeader(FResDir).wCount;
  773.     PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader);
  774.     ResList := FExeImage.FIconResources.List;
  775.     for I := 0 to Cnt - 1 do
  776.     begin
  777.       ResOrd := ResData.wNameOrdinal;
  778.       for J := 0 to ResList.Count - 1 do
  779.       begin
  780.         if ResOrd = ResList[J].FDirEntry.Name then
  781.         begin
  782.           IconResource := ResList[J] as TIconResEntry;
  783.           IconResource.FResInfo := ResData;
  784.           FList.Add(IconResource);
  785.         end;
  786.       end;
  787.       Inc(ResData);
  788.     end;
  789.   end;
  790.   Result := FList;
  791. end;
  792.  
  793. { TCursorResourceList }
  794.  
  795. function TCursorResourceList.List: TList;
  796. var
  797.   I, J, Cnt: Integer;
  798.   ResData: PCursorResInfo;
  799.   ResList: TResourceList;
  800.   ResOrd: Cardinal;
  801.   CursorResource: TCursorResEntry;
  802. begin
  803.   if not Assigned(FList) then
  804.   begin
  805.     FList := TList.Create;
  806.     Cnt := PIconHeader(FResDir).wCount;
  807.     PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader);
  808.     ResList := FExeImage.FCursorResources.List;
  809.     for I := 0 to Cnt - 1 do
  810.     begin
  811.       ResOrd := ResData.wNameOrdinal;
  812.       for J := 0 to ResList.Count - 1 do
  813.       begin
  814.         if ResOrd = ResList[J].FDirEntry.Name then
  815.         begin
  816.           CursorResource := ResList[J] as TCursorResEntry;
  817.           CursorResource.FResInfo := ResData;
  818.           FList.Add(CursorResource);
  819.         end;
  820.       end;
  821.       Inc(ResData);
  822.     end;
  823.   end;
  824.   Result := FList;
  825. end;
  826.  
  827. end.
  828.