Как решить проблему с записью иконки размером 256х256 в ресурсы *.exe файла?

Приветствую!

Задался целью научиться устанавливать произвольную иконку у произвольного *.exe файла. Все это нужно будет для будущего проекта.

Пишу я в Delphi, на данный момент полностью перешел на XE5 версию (до этого, использовал XE) ради x64 и Android.
Операционная система - Windows 8.1 Pro x64.

Сразу поставил себе задачу, найти (сделать) код, компилирующийся и подходящий для х32 и х64 исполняемых файлов.

Найти ничего подходящего не удалось, хотя были удачные решения. Решил, понять, как устроена (в каких ресурсах хранится, какой формат эти ресурсы имеются) вообще иконка у *.exe.

Прочитал внимательно эти два материала:
msdn.microsoft.com/en-us/library/ms997538.aspx
www.codeproject.com/Articles/30644/Replacing-ICON-...

Понял, что по сути это *.ico файл. Разница с которым в двух вещах:
1) Заголовок "сущности" меньше на 2 байта (у *.ico указывается смещение в файле - тип DWORD, а в случае приложением - указывается ID ресурса - тип WORD)
2) В *.ico файле все заголовки и данные включены в 1 файл, а в приложении - заголовки указываются в ресурсе RT_ICON_GROUP с именем 'MAINICON', а данные - в ресурсы RT_ICON числовым именем

Начал писать код.
Для начала сделал загрузку данных с *.ico файла и *.exe. Все получилось с первого раза, и работало без ошибок!

Далее, сделал сохранение полученных данных в *.ico - все отлично. Файл иконки получился идентичным по всем контрольным суммам с оригинальным (в том числе, который был вкомпилен в *.exe).

Вот на этапе сохранения в *.exe, сразу столкнулся с проблемой:
*.exe файл получался без иконки, хотя все ресурсы воде как присутствовали, но ResourceHacker - не мог прочитать их.
При этом все функции возвращали True.
Спрашивал на нескольких форумах, но никак не смог найти ответ.

Сохраняю, вот так:
procedure TdsIconResource.SaveToResource(aFileName: WideString; aLanguage: LANGID);
var
 entityid: Word;
 aStream: TMemoryStream;
 hUpdate: THandle;
 i: Integer;
 entity: TdsIconResourceEntity;
 procedure SpecialWrite(const Buffer; Count: Longint);
 var
  Writed: LongInt;
 begin
  Writed:=aStream.Write(Buffer, Count);

  if Writed <> Count then
   raise Exception.Create(Format('Writed fail, %d\%d', [writed, count]));
 end;
begin
 hUpdate:=BeginUpdateResourceW(PWideChar(aFileName), False);

 aStream:=TMemoryStream.Create;

 SpecialWrite(FHeader, SdsIconHeader);

 for I := 0 to FHeader.wCount - 1 do
  begin
   entity:=TdsIconResourceEntity(FEntities.Objects[i]);

   SpecialWrite(entity.FHeader, SdsIconEntityHeader);

   entityid:=i+1;

   SpecialWrite(entityid, SizeOf(Word));

   entity.FData.Position:=0;

   if not UpdateResourceW(hUpdate, RT_ICON, MAKEINTRESOURCE(entityid), aLanguage, entity.FData.Memory, entity.FData.Size) then
    raise Exception.Create('not UpdateResourceW~Icon~, '+IntToStr(GetLastError));
  end;

 aStream.Position:=0;

 if not UpdateResourceW(hUpdate, RT_GROUP_ICON, 'MAINICON', aLanguage, aStream.Memory, aStream.Size) then
  raise Exception.Create('not UpdateResourceW~Group~, '+IntToStr(GetLastError));

 if not EndUpdateResourceW(hUpdate, False) then
  raise Exception.Create('not EndUpdateResourceW, '+IntToStr(GetLastError));

 FreeAndNil(aStream);
end;


Сделал вот такое приложение:
gm7zfSP7UWTsEWrhp437w.jpg

Ссылка: floomby.ru/s2/E4d47u
(включает в себя различные варианты *.ico файлов, созданых в IcoFX из оригинала 256х256; само приложение; болванку х32 - консольное приложение, без какого-либо лишнего кода и ресурсов).

Болванка x64: floomby.ru/s2/54dWpb

В ходе тестов
Нашел причину, из-за которой почему то бьются ресурсы - это сущность иконки размером 256х256!

Если такая имеется, не важно будь то в *.ico файла или в ресурсах *.exe - то "болванка прожигается" криво - ресурсы бьются, исполняемый файл отказывается запускаться!

При этом, Delphi - компилирует с такой иконкой отлично!

В чем может быть дело?
И как можно исправить все это? И в какую сторону копать?

P.S.
Может быть поможете с еще одним вопросом? Я так понимаю, если взять указатель на данные ресурса RT_ICON - то бишь на сами данные сущности, без заголовка и привести к типу HICON - то мы получим готовый к использованию HICON?
Пробовал сделать TImage.Picture.Icon.Handle:=HIcon(...) - не выводит ничего!
  • Вопрос задан
  • 3168 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы