Strange AV while loading an icon from the resource stream

2

I'm adding icons to my project via Resources and Images dialog, and decided to walk away from TIcon.LoadFromResourceName because it does not perform any error checking. I wrote seemingly equivalent code but does not work as expected.

Here is a testcase which fails for me:

procedure TForm1.FormCreate(Sender: TObject);
const
  ResName = 'Icon_1';
var
  Stream: TResourceStream;
begin
  OutputDebugString(PChar(Format('RTLVersion = %f', [RTLVersion])));
  Assert(Assigned(Image1), 'Image1 comes from the designer, should be instantiated already');

  Stream := TResourceStream.Create(HInstance, ResName, RT_GROUP_ICON);
  try
    Image1.Picture.Icon.LoadFromStream(Stream); // AV here
  finally
    Stream.Free;
  end;
end;

A/V occurs deeply inside library at write of address 0x00000008, which suggest some uninitialized object instance.

I'm doing anything wrong or it is a library bug? Library version is 23.0, Delphi XE2

delphi
resources
icons
delphi-xe2
asked on Stack Overflow May 2, 2013 by OnTheFly • edited May 2, 2013 by OnTheFly

2 Answers

3

I was confusing RT_GROUP_ICON and RT_ICON. RT_GROUP_ICON contains only icon header and directory (GRPICONDIR and GRPICONDIRENTRY respectively), but actual images and masks are stored separately as RT_ICON resources. Additionally, icon file headers and icon group headers have exactly same layout and magic values, making detection of invalid data stream impossible. Therefore, it is absolutely not possible to use TIcon.LoadFromStream with RT_GROUP_ICON resource, this method has been designed for disk files only.

Thanks to bummi for shedding a light onto this nuance.

Additional reading: LookupIconIdFromDirectoryEx function reference and the corresponding example code.

answered on Stack Overflow May 2, 2013 by OnTheFly • edited Apr 1, 2019 by Z80
1

I do not know if you can load an RT_GROUP_ICON resource into a TIcon using LoadFromStream(), but there are alternate solutions:

Image1.Picture.Icon.Handle := LoadIcon(HInstance, ResName);

Or:

Image1.Picture.Icon.Handle := LoadImage(HInstance, ResName, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);

Or:

Image1.Picture.Icon.Handle := CreateIconFromResourceEx(PByte(Stream.Memory), Stream.Size, TRUE, $00030000, 0, 0, LR_DEFAULTSIZE);
answered on Stack Overflow May 2, 2013 by Remy Lebeau

User contributions licensed under CC BY-SA 3.0