home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1997 August / VPR9708A.ISO / D3TRIAL / INSTALL / DATA.Z / EXEIMAGE.PAS < prev    next >
Pascal/Delphi Source File  |  1997-04-24  |  21KB  |  805 lines

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