Приветствую!Задался целью научиться устанавливать произвольную иконку у произвольного *.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;
Сделал вот такое приложение:
Ссылка:
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(...) - не выводит ничего!