Reputation: 956
I want to change a formerly generated EXE file's main icon using Delphi. The EXE file was also generated by me using Delphi. But I want the user to be able to change its icon.
I tried using UpdateResource function to change RT_GROUP_ICON and RT_ICON without success:
procedure UpdateExeIcon(Const IconFilename, ExternalExeFilename:string);
var
Stream : TFileStream;
hDestRes : THANDLE;
lpData : Pointer;
cbData : DWORD;
begin
Stream := TFileStream.Create(IconFilename,fmOpenRead or fmShareDenyNone);
try
Stream.Seek(0, soFromBeginning);
cbData:=Stream.Size;
if cbData>0 then
begin
GetMem(lpData,cbData);
try
Stream.Read(lpData^, cbData);
hDestRes:= BeginUpdateResource(PChar(ExternalExeFilename), False);
if hDestRes <> 0 then
begin
//if UpdateResource(hDestRes, RT_ICON,PChar('1'),1033,lpData,cbData) then
if UpdateResource(hDestRes, RT_GROUP_ICON,PChar('MAINICON'),1033,lpData,cbData) then
begin
if not EndUpdateResource(hDestRes,FALSE) then RaiseLastOSError;
end else RaiseLastOSError;
end else RaiseLastOSError;
finally
FreeMem(lpData);
end;
end;
finally
Stream.Free;
end;
end;
Upvotes: 1
Views: 691
Reputation: 6099
There are multiple mistakes:
UpdateResource(hDestRes, RT_ICON,PChar('1'),1033,lpData,cbData)
the lpName
parameter works in two ways: PChar('1')
will turn out as a text, while MakeIntResource(1)
will turn out as a number. You want the latter variant, not the former.RT_ICON
you have to provide the actual Icon payload, not an entire Icon file. Right now you do the latter, not the former. Look at how an Icon file looks like, then look at what the resource only has.RT_GROUP_ICON
is "only" an index describing existing RT_ICON
resources and should be patched as per your updated Icon (unless width, height, colors, pixel depth and payload length are all the same). Filling in file contents here makes never sense.Above you see Resource Hacker displaying the raw bytes of the resource we want to update. 128
is the length of bytes in hexadecimal.
Above you see HxD displaying a whole Icon file - I selected the part where the first icon payload resides: starting at offset 26
with a length of 128
(both hexadecimal). Both byte sequences match.
If you do all that (using MakeIntResource(1)
on RT_ICON
and provide only the picture data of the Icon file) then you're fine - it worked for me fine: my EXE then displayed the new icon in Windows' Explorer (haven't executed it, tho). Updating the RT_GROUP_ICON
should also be done, since I'm not sure up to where it seems to have no effect and when it suddenly becomes a problem. Viewing your files in a hex editor and your EXE in a resource editor will make you understand much better all the actions. Further reading:
Upvotes: 5