Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Change icon

Posted on 2007-10-07
21
Medium Priority
?
1,704 Views
Last Modified: 2008-01-09
Hi,

Do you know any way how to change .exe icons using Delphi ?

I tried "madRes" from madshi.net, but it can only change the "main icon" (icon that is displayed by Windows Explorer). At least I use the example from madshi website.

I need to change icons properly, the one that is displayed by Windows Explorer, the one that is displayed in the taskbar, the one in the top left Delphi TForm ...

Please if you know how to do that.

Thanks.
0
Comment
Question by:kapot
21 Comments
 
LVL 28

Expert Comment

by:2266180
ID: 20032836
all the icons you enumerated are 1 icon: the main icon. but that icon is a multi-page icon. so it's one ico file that contains a few icons of different sizes which are autoamtically picked by windows when needed: in a small area, like taskbar, a small icon is choosen. in a big era like when viewing icons in explorer, a bigger icon is choosen.
in case there are any other icons in the exe, you can also change them too using madres, but instead of providing MAINICON, you will need to provide the correct group. in order ot know the correct group, you need a resource editor to see the group. for example xn resource editor http://www.wilsonc.demon.co.uk/d10resourceeditor.htm
0
 

Author Comment

by:kapot
ID: 20033017
I checked using ResHack and I saw another group of icon "128" besides "MAINICON".

I changed the group "128", but the result is ... madReas added a new "128" group instead of changing it.

Then I checked again using ResHack, the correct "128" group has "1033" sub-group.

The added "128" has "0" sub-group.

Still cant figure out using madRes.
0
 

Author Comment

by:kapot
ID: 20033019
Here is the function that I use to change EXE icon :

function UpdateExeIcon(exeFile, iconGroup, icoFile: string) : boolean;
var resUpdateHandle : dword;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then begin
    result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), 0, PWideChar(wideString(icoFile)));
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 

Author Comment

by:kapot
ID: 20033047
I also tried to add that "language" parameter :

function UpdateExeIcon(exeFile, iconGroup, icoFile: string; language: word) : boolean;
var resUpdateHandle : dword;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then begin
    result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, PWideChar(wideString(icoFile)));
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;

But that does not help. It created a duplicate entry of the same icon group !
0
 
LVL 28

Expert Comment

by:2266180
ID: 20033146
well .. then you are not interpreting the data correctly.

here is my test (using xn resource editor)
- exe file with 3 icons:
-- MAINICON (language is my local language)
-- ICON1 (language neutral)
-- ICON2 (language neutral)

function UpdateExeIcon(exeFile, iconGroup, icoFile: string; language: word) : boolean;
var resUpdateHandle : dword;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then begin
    result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, PWideChar(wideString(icoFile)));
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  UpdateExeIcon('c:\test.exe', 'ICON1', 'c:\test.ico', 0);
end;

the icon is beeing correctly replaced.
so, I am guessing that your non-main icons are not language neutral and since you are using 0, the new icon is added.

btw, I'm using
madRes.pas                version:  1.0j  ·  date: 2005-07-15
0
 

Author Comment

by:kapot
ID: 20033813
In my case,

The MAINICON is using language = neutral

and the other icon group is "128" using language = English US.

I tried to change that "128" icon group using language = 1033

And it does not work.

Maybe if we can find a way to LIST all the icon groups and the language?
0
 
LVL 28

Expert Comment

by:2266180
ID: 20033939
well, that depends a little on what you are doing.
so before getting into more details, lets start with the begining:
- what excatly are you trying to do?
- how do you know which icon you want to modify?
0
 
LVL 9

Expert Comment

by:sun4sunday
ID: 20038757
Are you looking to change the icon of your exe ? Then go to
Project > Options > Application Tab > Click  'Load Icon' button
You can choose the ico extension icons which will set for the exe icon as well as for the forms.
0
 

Author Comment

by:kapot
ID: 20049013
I want to change the icon of an EXE file during runtime.

I meant something like this: I have a main application called PUBLISHER.EXE which can be used to change any EXE file icon.

So the EXE file that I want to change is different EXE file, not the PUBLISHER.EXE.

Using the madRes unit, I can only change the MAINICON Icon Group, not other icons.

That's my current problem.
0
 
LVL 28

Expert Comment

by:2266180
ID: 20049149
kapot, still one question unanswered:
- how do you know which icon you want to modify?
0
 

Author Comment

by:kapot
ID: 20055499
Ciuly,

At this moment, I use ResHack or Wilson Resource Editor to "see" which icon group that need to be changed.

Then I tried the madRes unit to change that, which it failed.

I can see MAINICON with language code = 0, also "128" with language code = 1033.

But as I mentioned, madRes could not change the one with language code 1033. It will create duplicate, same "128" icon group and same language code 1033.

It would be nice if we can enumerate (make a list) of available icon group and its language code and then change it programatically.

I am thinking there is a bug in the madRes unit so it cannot REPLACE icon group other than MAINICON, or it cannot replace if the language code is not 0.
0
 
LVL 28

Expert Comment

by:2266180
ID: 20055907
>>I am thinking there is a bug in the madRes unit so it cannot REPLACE icon group other than MAINICON,
as I told you, this worked for me. so this is out of the question

>> or it cannot replace if the language code is not 0.
this is false as well.

one thread worth reading: http://forum.madshi.net/viewtopic.php?t=273

I've made some tests and found that the problem is the resource group name beeing "128". if you rename that to anything else (non-numeric), than you can change the icon without problems.

I'm using the following code:

program Project2;

uses
  windows, madres;

{$R *.res}

function MAKELANGID(sPrimaryLanguage : Word;
                    sSubLanguage : Word) : Word;
begin
  result := (sSubLanguage shl 10) or
             sPrimaryLanguage;
end;

function UpdateExeIcon(exeFile, iconGroup, icoFile: string; language: word) : boolean;
var resUpdateHandle : dword;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then begin
    result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, PWideChar(wideString(icoFile)));
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;

begin
  UpdateExeIcon('test.exe', 'TEST', 'red.ico', makelangid(LANG_ENGLISH,SUBLANG_ENGLISH_US));
end.

created a test application:

program Project1;

{$R *.res}
{$R icons.res}

begin
end.

and the icon resource:icons.rc
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
128 ICON "green.ico"
TEST ICON "green.ico"

compiled with brcc32 icons.rc resulting in icons.res

then compiled project1 and renamed to test.exe and then run project2 and the test icon changed from green to red as expected. language stood the same. no new groups added
if I change 'TEST' to '128' in project 2, then this is no longer true.

I will post on madshis forum and see what he has to say about this.

an alternative would be to use the xn resource components/classes
0
 
LVL 11

Expert Comment

by:ZhaawZ
ID: 20058625
>> I need to change icons properly, the one that is displayed by Windows Explorer, the one that is displayed in the taskbar, the one in the top left Delphi TForm ...

Those icons don't have to be the same actually. iirc, the first icon in resources is the one that is visible in Explorer (it can be multipage icon for multiple icon sizes / colors). Other icons (in taskbar, in form's corner, in alt+tab window) may be whatever that exact application loads as window's icon. For "standard windows" those 3 icons are the same icon (which can be multipage icon for displaying "different" icons when different sizes are needed), which is loaded before calling RegisterClass() or RegisterClassEx(). With "standard window" I mean a window that is visibile in taskbar and as a window on desktop. In Delphi applications you actually don't see forms (TForm*) in taskbar; instead you see TApplication which may have different icon than forms (you don't see TApplication as a window, you see it only in taskbar; you don't see forms in taskbar, you see only windows on desktop).

If there is one exact program you want to play with, you can, of course, try to figure out, which icon is where, but I think there is not a universal way for changing icons in all applications (for .exe file - there is; for forms' corner / taskbar - there is not).
0
 
LVL 21

Expert Comment

by:developmentguru
ID: 20064557
I am coming into this conversation late, so pardon me if I ask any redundant questions.  I have the sneaking suspicion that the icon you are trying to change may be accessed by text 128 (as opposed to numeric 128).  It is also possible that the icon text 128 may be something like '128 ' (with a space).  It would help us all greatly if we had access to the EXE in question...

Let me know.
0
 
LVL 28

Expert Comment

by:2266180
ID: 20064888
you can generate it yourself with the info I've given above. you have the rc file there as well, you can create the icons in whatever you like (or just grab 2 from somewhere).
I just tried using #128, ' 128', '128 ' but same behaviour.
I looked in the binary file and the data is stored like this:
0B 00 P 00 A 00 C 00 K 00 A 00 G 00 E 00 I 00 N 00 F 00 O 00  (PACKAGEINFO)
08 00 M 00 A 00 I 00 N 00 I 00 C 00 O 00 N 00 (MAINICON)
04 00 T 00 E 00 S 00 T 00 (TEST)
00 00 (I would have expected this to be 128, but it's not)
28 00 00 20 00 blablabla

anyway, I made a small trace through madres and it seems that it just doesn't load that icon at all.
I'll do some more research shortly.
0
 
LVL 28

Expert Comment

by:2266180
ID: 20064994
ok. found the problem and fixed it :)

correct function is here:

program Project2;

uses
  windows,
  madres,
  sysutils;

{$R *.res}

function MAKELANGID(sPrimaryLanguage : Word;
                    sSubLanguage : Word) : Word;
begin
  result := (sSubLanguage shl 10) or
             sPrimaryLanguage;
end;

function UpdateExeIcon(exeFile, iconGroup, icoFile: string; language: word) : boolean;
var resUpdateHandle : dword;
    c:TPIconGroup;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then
  begin
    if GetIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, c) then
      result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, PWideChar(wideString(icoFile)))
                                                                                             else
    if StrToIntDef(iconGroup, -1)>-1 then
      result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(pointer(strtoint(iconGroup))), language, PWideChar(wideString(icoFile)))
    else
      result := false;
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;

begin
  UpdateExeIcon('test.exe', '128', 'red.ico', makelangid(LANG_ENGLISH,SUBLANG_ENGLISH_US));
end.
0
 

Author Comment

by:kapot
ID: 20066974
Ciuly ! You are genius! :)

However, there is one problem: It seems, I cannot change the 'MAINICON' like this :

UpdateExeIcon('test.exe', 'MAINICON', 'red.ico', 0);

Could that be because of the language = 0 ? I need that 0 btw.
0
 

Author Comment

by:kapot
ID: 20066981
Btw, could you also explain to me in a very short sentence ... what was the problem with the original function? You said that you found the problem and fixed it :)
0
 
LVL 28

Expert Comment

by:2266180
ID: 20068331
the problem was that the 128 was saved as a numebr, not a text. so you needed to pass it the number (see the string to integer to pointer to pwidechar conversion there? that's how the number is passed)

I'll have to look into the mainicon thingie.
0
 
LVL 28

Accepted Solution

by:
2266180 earned 2000 total points
ID: 20068372
got it. here is the final function:

function UpdateExeIcon(exeFile, iconGroup, icoFile: string; language: word) : boolean;
var resUpdateHandle : dword;
    c:TPIconGroup;
begin
  resUpdateHandle := BeginUpdateResourceW(PWideChar(wideString(exeFile)), false);
  if resUpdateHandle <> 0 then
  begin
    if (icongroup='MAINICON') or GetIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, c) then
      result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(wideString(iconGroup)), language, PWideChar(wideString(icoFile)))
                                                                                             else
    if StrToIntDef(iconGroup, -1)>-1 then
      result := LoadIconGroupResourceW(resUpdateHandle, PWideChar(pointer(strtoint(iconGroup))), language, PWideChar(wideString(icoFile)))
    else
      result := false;
    result := EndUpdateResourceW(resUpdateHandle, false) and result;
  end else
    result := false;
end;

use correct language and it will work. I haven't debugged this to see why GetIconGroupResourceW is not seeing the MAINICON, I just had a hunch and went for it :)
0
 

Author Comment

by:kapot
ID: 20102554
Thanks ciuly, you are the best !
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Suggested Courses
Course of the Month11 days, 10 hours left to enroll

564 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question