Link to home
Start Free TrialLog in
Avatar of Goomoo
Goomoo

asked on

How to change an EXE file's icon by programming?

How to change an EXE file's icon by programming?

Please give me some codes or an example.

Best regards.


Goomoo
Avatar of Goomoo
Goomoo

ASKER

Why not someone can help me?
You can do that only if the exe is currently not running. In that situation you can use BeginUpdateResourceW and related functions to change the resources of the exe. The EXE's icon is stored in the resources. If you change the icon in the resources, you'll also change the EXE's icon. BeginUpdateResourceW is only available in the NT family, it's not available in 9x. But you can use my free unit "madRes" (part of the free package "madBasic"), which makes BeginUpdateResourceW available in 9x, too.

Sorry, can't give you code, have no time for that.

www.madshi.net
What exactly are you trying to do...

Are you wanting to write a delphi app that can change the icons in other delphi apps? or any other apps?
Or perhaps you want a delphi program that can change its own icon?

Are you creating a general utility to let others change the icons in whatever exe files they like?

Or do you just need to USE a utility that can change other exe's icons? if so try ResHack.exe .. it is a nice freeware delphi app that can work with the resources of an exe file... you can change icons easily using this tool.

If you want to add code to your own programs to let them alter the icons of other executables then madshi's code is just what you need... I don't think it can change the icon of an exe that has been been compressed along with its resources.... to do that you will need to add de-compression code for all of the commercial and freeware compressors... a big task!   or just tell your users that the exe must be uncompressed or the icons cannot be changed.


Avatar of Goomoo

ASKER

Thank you, Madshi.
Thank you, Gwena.

I want to change a Delphi app's icon. The exe-file has been compressed by UPX. I have changed the exe-file's icon by ExeScope successfully, But I hope I can change the file's icon by codes.

or

Who can show me an example,how to change a non-compressed exe-file's icon?
Using my unit madRes it's fairly easy:

- BeginUpdateResourceW (exe file path)
- LoadIconGroupResourceW (new ico file path)
- EndUpdateResourceW

That's it. Just give in the correct parameters. Must be wide strings. See here for documentation:

http://help.madshi.net/madResUnit.htm

Here's a direct download:

http://madshi.bei.t-online.de/madCollectionBeta.exe

Regards, Madshi.
ASKER CERTIFIED SOLUTION
Avatar of Gwena
Gwena

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Overwriting the sectors won't help here, because depending on which color depths and resolutions the old and the new icon supports, the resource section can grow or get smaller.
P.S: UPX is nice, but it has one problem: It changes the addresses of all functions. As a result my exception tracker "madExcept" doesn't work with UPX compressed exes. Petite and AsPack don't change the addresses of the functions.
Yup... you have to pad out the exe so that the original has room to be grown. When I used to modify exe files directly at the sector level I would add a bunch of stuff to the end so I had room to spare...then check to see which bytes of my modified copy were different from the original and insert every changed byte into the sectors holding the original.... the exes never minded that a bunch of padding was left at the end... but it is a bit of a kludge... actually the whole idea of modifying an exe directly on the disk is risky... that's where the praying comes in handy :-)

I understand about the differing icon types and sizes.. I made an exe that could change its icon directly using exemod... but it only worked with icons of the exact same size/type... I suppose that is worth something if you were to originally use a large icon and somehow convert any new one a user chose into the same type before you inserted it.

Thanks for the info about UPX,AsPack and Petite... that's good stuff to know :-)
{
   Copyright 2003-2004 by Sima Huapeng
   smhp@163.net
}
unit Pak;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, shellApi;

type
  TexePak = class(TComponent)
  private
    fSourceFile: string;
    fDestFile: string;
    fOutFile: String;
   
    procedure SetSourceFile(const Value: string);
    procedure SetDestFile(const Value: string);
    procedure SetOutFile(const Value: string);
  protected

  public
    constructor Create(AOwner: TComponent); reintroduce;
    destructor Destroy; override;

    function ExchangeExeIcon:Boolean;

    property SourceFile: string read fSourceFile write SetSourceFile;
    property DestFile: string read fDestFile write SetDestFile;
    property OutFile: string read fOutFile write SetOutFile;
  published

  end;

implementation

constructor TexePak.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
end;

destructor TexePak.Destroy;
begin
  inherited;
end;

function TexePak.ExchangeExeIcon():Boolean;
const
    readlen=10;                     //每次读取字节数,可改变
    icolen=766;                     //32*32图标长度,根据研 究前126为 图标头,后640为图 标数据
var
    i,j,itemp,nPos:int64;           // nPos为目的图标在目的文 件的位置
    ci,cj:array[0..readlen-1] of char;
    bOK:boolean;
    SourceIcon,DestIcon:TIcon;
    SIconStream,s,sDest:TMemoryStream;
begin
    Result:=False;
    bOK:=false;
    if ExtractIcon(0,PChar(fSourceFile),UINT(-1))=0 then exit;
    SourceIcon:=TIcon.Create;
    try
        try
            SourceIcon.Handle:=ExtractIcon(0,PChar(fSourceFile),0);      //选择第一个图标
            if ExtractIcon(0,PChar(fDestFile),UINT(-1))=0 then exit;
            DestIcon:=TIcon.Create;
            try
                DestIcon.Handle:=ExtractIcon(0,PChar(fDestFile),0);//选择第一个图标
                SIconStream:=TMemoryStream.Create;
                try
                  DestIcon.SaveToStream(sIconStream);
                  SDest:=TMemoryStream.Create;
                  try
                    sDest.LoadFromFile(fDestFile);
                    i:=0;j:=0;   //以下程序查找 目的图标在目的程序 中的位置
                    while  i<sDest.size do
                    begin
                         itemp:=i;
                         j:=126;
                         ci:='';cj:='';
                         while (String(ci)=String(cj)) and (i<SDest.size) and (j<icolen) do
                         begin
                                  i:=i+readlen;
                                  j:=j+readlen;
                                  SDest.Position:=i;
                                  SDest.read(ci,readlen);
                                  SiconStream.Position:=j;
                                  SiconStream.Read(cj,readlen);
                         end;
                         if j<icolen then
                              i:=itemp+1  //&#27809;&#25214;&#21040;
                         else
                         begin
                             nPos:=itemp;  //&#25214;&#21040;
                             bOK:=true;
                             break;
                         end;
                    end;
                    if bOK=false then exit;//&#30446;&#26631;&#25991;&#20214;&#20108;&#36827;&#21046; &#30721;&#20013;&#26410;&#25214;&#21040;&#22270;&#26631;
                    SIconStream.Clear;//&#23558;&#28304;&#31243;&#24207;&#22270;&#26631;&#23384;&#20837;
                    SourceIcon.SaveToStream(SIconStream);
                    SIconStream.position:=126;
                    s:=TMemoryStream.Create;
                    try
                        sDest.Position:=0;
                        s.CopyFrom(sDest,nPos);//&#23558;&#30446;&#30340;&#31243;&#24207;&#22270;&#26631;&#21069;&#25968;&#25454;&#25335;&#20837;
                        s.CopyFrom(SIconStream,640); //&#23558;&#28304;&#31243;&#24207;&#22270;&#26631;&#25335;&#20837;
                        if sDest.size>sDest.Position+640 then //&#23558;&#30446;&#30340;&#31243;&#24207;&#21097;&#20313;&#25968;&#25454;&#25335;&#20837;
                        begin
                             sDest.Position:=sDest.Position+640;
                             s.CopyFrom(sDest,sDest.Size-sDest.Position);
                        end;
                        s.SaveToFile(fOutFile);   //&#25913;&#36896;&#22909;&#30340;&#31243;&#24207;&#23384; &#25918;&#22312;OutFile&#25991;&#20214;&#20013;
                    finally
                        S.Free;
                    end;
                  finally
                    sDest.Free;
                  end;
                finally
                  SIconStream.Free;
                end;
            finally
                DestIcon.Free;
            end;
        finally
            SourceIcon.Free;
        end;
    except
        Result:=False;
        Exit;
    end;
    Result:=True;
end;

procedure TexePak.SetDestFile(const Value: string);
begin
  fDestFile := value;
end;

procedure TexePak.SetOutFile(const Value: string);
begin
  fOutFile := Value;
end;

procedure TexePak.SetSourceFile(const Value: string);
begin
  fSourceFile := Value;
end;

end.
 
Interesting code
But why icon size 766 ?
Is this the size of an 16*16 Icon with 16 colors?
Is it possible to do this also for 32 bit or 256 color icons?

If this approach works for those icons I d like to ask this question in an own thread
erm just use madshi's source works brill used it my self with my installer,
which madshi isnt quite finished yet :D

that code u have wrote out only acumpesses for one icon type how ever xp suports

32bit alpha channel icons and also they can be any size not just 16x16 or 32x32 but stuff like 512x512
my msn:end_sub@hotmail.com
here a class for modifing icon from win2000 or later.
                                                   ~~~~~~~~~~~


unit IconModifyUnit;

interface

uses Windows, SysUtils, Classes ;

type
  TIconModifier = Class(TComponent)
  private
    FSourceFile : String ;
    FDestFile   : String ;
    procedure SetSourceFile(AFile: String) ;
    procedure SetDestFile(AFile: String) ;
    function  ModifyIconForNt(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
    function  ModifyIconFor9x(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
  public
    property  SourceFile: String Read FSourceFile Write SetSourceFile ;
    property  DestFile  : String Read FDestFile Write SetDestFile ;
    function ModifyIcon(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
  end;

implementation


procedure TIconModifier.SetSourceFile(AFile: String);
begin
  FSourceFile := AFile ;
end;

procedure TIconModifier.SetDestFile(AFile: String);
begin
  FDestFile := AFile ;
end;

function TIconModifier.ModifyIconForNt(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
var
  hModule  : Cardinal ;
  hResFind : Cardinal ;
  hResLoad : Cardinal ;
  pResLock : PChar ;
  hResUpdate: Cardinal ;
begin
  Result := false ;

  hModule := LoadLibrary(PChar(FSourceFile));
  if hModule = 0 then
    Exit ;

  try
    hResFind := FindResource(hModule, MakeIntResource(SourceIndex+1), RT_ICON) ;
    if hResFind = 0 then
      Exit ;

    hResLoad := LoadResource(hModule, hResFind) ;
    if hResLoad = 0 then
      Exit ;

    pResLock := LockResource(hResLoad) ;
    if pResLock = nil then
      Exit ;

    hResUpdate := BeginUpdateResource(PChar(FDestFile), false) ;
    if hResUpdate = 0 then
      Exit ;

    if not UpdateResource(hResUpdate,
                          RT_ICON,
                          MakeIntResource(DestIndex + 1),
                          0, //local language
                          pResLock,
                          SizeofResource(hModule, hResFind)) then
      Exit ;

    if not EndUpdateResource(hResUpdate, false) then
      Exit ;
  finally
    FreeLibrary(hModule) ;
  end;
  Result := true ;
end;

function TIconModifier.ModifyIconFor9x(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
begin
  Result := false ;
end;

function TIconModifier.ModifyIcon(SourceIndex, DestIndex: Cardinal = 1): Boolean ;
begin
  Result := false ;
  if Win32PlatForm = VER_PLATFORM_WIN32_NT then
    Result := ModifyIconForNt(SourceIndex, DestIndex)
  else
    Result := ModifyIconFor9x(SourceIndex, DestIndex) ;  // not implement now.
end;
end.



example &#65306;

use IconModifyUnit ;

procedure TForm1.Button1Click(Sender: TObject);
var
  im : TIconModifier ;
  source, dest: String ;
begin
  if OpenDialog1.Execute then
    source := OpenDialog1.FileName
  else
    Exit ;

  if OpenDialog2.Execute then
    dest := OpenDialog2.FileName
  else
    Exit ;


  im := TIconModifier.Create(Self) ;
  im.SourceFile := source ; //a file includes source icon(s),  exe or dll format.
  im.DestFile := dest ; //file includes icon which will be modified. exe or dll.
  if im.ModifyIcon(1) then
    MessageBox(Handle,'successful.', 'info', MB_OK + MB_ICONINFORMATION)
  else
    MessageBox(Handle,'fail.', 'info', MB_OK + MB_ICONINFORMATION) ;
  im.Free ;
 
end.



08 13, 2004
Regards, adayuer
Thanks a lot.
Can file no 1 be an icon itself or must it be an exe or dll?

Thanks anyway

cheers
hh
win32 app (exe) usually has ONE icon at least, the icon's index from 1 to all Icons count, but sometimes, if app has a icongroup,more than one icon in the icongroup, the icon's index is hard to get.


my msn : adayuer@msn.com