procedure TForm1.Button1Click(Sender: TObject);
var vResHandle: THandle;
MyIcon: TMemoryStream;
i,j: integer;
s: string;
ImageCount: Word;
ImageSize: DWord;
ab, m: TMemoryStream;
const HeaderSize = 6;
IcoEntrySize = 16;
ResEntrySize = 14;
begin
// Short explanation. An icon file consists of (a) a six-byte header which
// includes among other things information about how many icons are in
// the file; (b) sixteen bytes of metadata for each icon; (c) the icons.
// But that's how icons are stored as files. As executable resources,
// Windows considers that (a) and (b) are one resource but (c) is a different
// resource, indeed one resource for each image, so we have to split the icon
// file up and do several resource updates.
// It also requires only fourteen bytes of metadata per entry: instead of the
// last parameter being a double word referring to the position of the image
// in memory, it's a single word conferring an ID.
// Initialize stuff
MyIcon := TMemoryStream.Create;
ab := TMemoryStream.Create;
m := TMemoryStream.Create;
// Get the icon
MyIcon.LoadFromFile('icon.ico');
// Get the handle for the resource update..
vResHandle := BeginUpdateResource('test.exe', False);
// We skip forward in the memory stream to where Windows keeps the image count and read it.
MyIcon.Seek(4,soFromBeginning);
ImageCount:=MyIcon.ReadWord;
// Go back to the beginning ...
MyIcon.Seek(0,soFromBeginning);
// We read the directory information into ab, modifying its format as we do so.
for j:=1 to HeaderSize do ab.WriteByte(MyIcon.ReadByte);
for i:=1 to ImageCount do
begin
for j:=1 to IcoEntrySize - 4 do ab.WriteByte(MyIcon.ReadByte);
MyIcon.ReadDWord; // To skip over it.
ab.WriteWord(i);
end;
// Update the icon directory with ab, which is now in the correct format.
UpdateResource(vResHandle
, RT_GROUP_ICON
, PChar('MAINICON')
, LANG_NEUTRAL
, ab.Memory
, ab.Size);
// Now the size of each icon is contained as a double word in the directory
// entries for each item, so we use that to cut the remainder of the memory
// stream into chunks and update them one at a time.
for i := 1 to ImageCount do
begin
m := TMemoryStream.Create;
ab.Seek(HeaderSize+(i-1)*ResEntrySize+8,soFromBeginning);
ImageSize:=ab.ReadDWord;
for j:=1 to ImageSize do m.WriteByte(MyIcon.ReadByte);
UpdateResource(vResHandle
, RT_ICON
, MAKEINTRESOURCE(i)
, LANG_NEUTRAL
, m.Memory
, m.Size);
m.Free;
end;
EndUpDateResource(vResHandle,False);
MyIcon.Free;
ab.Free;
end;