Jaymol
asked on
Change another app's icon.
Hi. I want to change the icon of a running application (NOT my application.) I want to be able to use my own icon for notepad (for example.)
I can set the window size, title, etc., but can't figure out the icon.
I've put this at 150 points cos I think it's not particularly easy, and I also want an example of it. Like I said, just an example that shows notepad with a different icon.
Thanks,
John.
I can set the window size, title, etc., but can't figure out the icon.
I've put this at 150 points cos I think it's not particularly easy, and I also want an example of it. Like I said, just an example that shows notepad with a different icon.
Thanks,
John.
ASKER
Is that the only way of doing it Neil? (Do you know?)
John.
John.
ASKER
Also, is the icon always in the same location, or is there a particular way of locating it in the exe?
John.
John.
hello,
you mean at runtime ??
they must be another way because programs like windowsblinds are doing it.
must I think this involves using a system wide hook, or such hard stuff. I don't know how to do this...
you mean at runtime ??
they must be another way because programs like windowsblinds are doing it.
must I think this involves using a system wide hook, or such hard stuff. I don't know how to do this...
ASKER
I'm quite happy to do it Neil's way, as long as I know where the icon is in the executable and what format to write it.
John.
John.
John,
I wasn't serious but if you really want to know (and there's probably a far better way than this)...
Extract the program's icon and then search through the EXE looking for the same set of bytes as the icon. At the same time you need to be copying the bytes that AREN'T what you want across into another file. When you hit the bytes that you DO want, write out the new byte pattern (which must be the same length), ignoring the bytes of the original icon. Then just copy across all the other bytes and copy your new file over the old one. It's a few years since I actually hacked a piece of code like this together (and I don't know where the source is) but I think the data MIGHT be stored backwards and you have to allow for the mask as well as the image
The Neil
I wasn't serious but if you really want to know (and there's probably a far better way than this)...
Extract the program's icon and then search through the EXE looking for the same set of bytes as the icon. At the same time you need to be copying the bytes that AREN'T what you want across into another file. When you hit the bytes that you DO want, write out the new byte pattern (which must be the same length), ignoring the bytes of the original icon. Then just copy across all the other bytes and copy your new file over the old one. It's a few years since I actually hacked a piece of code like this together (and I don't know where the source is) but I think the data MIGHT be stored backwards and you have to allow for the mask as well as the image
The Neil
ASKER
That doesn't sound too troublesome, but I could do with some help regarding the format of the icon. I'm basically going to be opening an executable that I've not touched before and supposed to be able to find the icon within it. I can't leave any part of this down to manual operation - It has to all be automatic, as in "Put new icon in file X", and that's it!
John.
John.
John,
Below is some code for extracting an icon from an EXE and when you read through the algorithm then you'll realise why I included it.
What you need to do is:
1.Extract the icon from the EXE that you're interested in (see the code below)
2.Load the extracted icon into an array of byte
3.Open the EXE file as FILE OF BYTE
4.Read bytes from the EXE file looking for a match with your array of stored icon data
5.When you match the set of data (the ENTIRE set, don't make any assumptions) copy your new icon file in (make sure that they're the same size by the way or you're in trouble)
6.Copy the rest of the EXE file across byte by byte
You can speed the whole thing up by using memory streams but I was useless when I did it and just stuck to files.
The Neil =:)
type ThIconArray = array[0..0] of hIcon;
type PhIconArray = ^ThIconArray;
function ExtractIconExA(lpszFile: PAnsiChar;
nIconIndex: Integer;
phiconLarge : PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExA';
function ExtractIconExW(lpszFile: PWideChar;
nIconIndex: Integer;
phiconLarge: PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExW';
function ExtractIconEx(lpszFile: PAnsiChar;
nIconIndex: Integer;
phiconLarge : PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExA';
procedure TForm1.Button1Click(Sender : TObject);
var
NumIcons : integer;
pTheLargeIcons : phIconArray;
pTheSmallIcons : phIconArray;
LargeIconWidth : integer;
SmallIconWidth : integer;
SmallIconHeight : integer;
i : integer;
TheIcon : TIcon;
TheBitmap : TBitmap;
begin
NumIcons :=
ExtractIconEx('C:\Program Files\Borland\Delphi 3\BIN\delphi32.exe',
-1,
nil,
nil,
0);
if NumIcons > 0 then begin
LargeIconWidth := GetSystemMetrics(SM_CXICON );
SmallIconWidth := GetSystemMetrics(SM_CXSMIC ON);
SmallIconHeight := GetSystemMetrics(SM_CYSMIC ON);
GetMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
GetMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
FillChar(pTheLargeIcons^, NumIcons * sizeof(hIcon), #0);
FillChar(pTheSmallIcons^, NumIcons * sizeof(hIcon), #0);
ExtractIconEx('C:\Program Files\Borland\Delphi 3\BIN\delphi32.exe',
0,
pTheLargeIcons,
pTheSmallIcons,
numIcons);
{$IFOPT R+}
{$DEFINE CKRANGE}
{$R-}
{$ENDIF}
for i := 0 to (NumIcons - 1) do begin
DrawIcon(Form1.Canvas.Hand le,
i * LargeIconWidth,
0,
pTheLargeIcons^[i]);
TheIcon := TIcon. Create;
TheBitmap := TBitmap.Create;
TheIcon.Handle := pTheSmallIcons^[i];
TheBitmap.Width := TheIcon.Width;
TheBitmap.Height := TheIcon.Height;
TheBitmap.Canvas.Draw(0, 0, TheIcon);
TheIcon.Free;
Form1.Canvas.StretchDraw(R ect(i * SmallIconWidth,
100,
(i + 1) * SmallIconWidth,
100 + SmallIconHeight),
TheBitmap);
TheBitmap.Free;
end;
{$IFDEF CKRANGE}
{$UNDEF CKRANGE}
{$R+}
{$ENDIF}
FreeMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
FreeMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
end;
end;
end.
Below is some code for extracting an icon from an EXE and when you read through the algorithm then you'll realise why I included it.
What you need to do is:
1.Extract the icon from the EXE that you're interested in (see the code below)
2.Load the extracted icon into an array of byte
3.Open the EXE file as FILE OF BYTE
4.Read bytes from the EXE file looking for a match with your array of stored icon data
5.When you match the set of data (the ENTIRE set, don't make any assumptions) copy your new icon file in (make sure that they're the same size by the way or you're in trouble)
6.Copy the rest of the EXE file across byte by byte
You can speed the whole thing up by using memory streams but I was useless when I did it and just stuck to files.
The Neil =:)
type ThIconArray = array[0..0] of hIcon;
type PhIconArray = ^ThIconArray;
function ExtractIconExA(lpszFile: PAnsiChar;
nIconIndex: Integer;
phiconLarge : PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExA';
function ExtractIconExW(lpszFile: PWideChar;
nIconIndex: Integer;
phiconLarge: PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExW';
function ExtractIconEx(lpszFile: PAnsiChar;
nIconIndex: Integer;
phiconLarge : PhIconArray;
phiconSmall: PhIconArray;
nIcons: UINT): UINT; stdcall;
external 'shell32.dll' name 'ExtractIconExA';
procedure TForm1.Button1Click(Sender
var
NumIcons : integer;
pTheLargeIcons : phIconArray;
pTheSmallIcons : phIconArray;
LargeIconWidth : integer;
SmallIconWidth : integer;
SmallIconHeight : integer;
i : integer;
TheIcon : TIcon;
TheBitmap : TBitmap;
begin
NumIcons :=
ExtractIconEx('C:\Program Files\Borland\Delphi 3\BIN\delphi32.exe',
-1,
nil,
nil,
0);
if NumIcons > 0 then begin
LargeIconWidth := GetSystemMetrics(SM_CXICON
SmallIconWidth := GetSystemMetrics(SM_CXSMIC
SmallIconHeight := GetSystemMetrics(SM_CYSMIC
GetMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
GetMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
FillChar(pTheLargeIcons^, NumIcons * sizeof(hIcon), #0);
FillChar(pTheSmallIcons^, NumIcons * sizeof(hIcon), #0);
ExtractIconEx('C:\Program Files\Borland\Delphi 3\BIN\delphi32.exe',
0,
pTheLargeIcons,
pTheSmallIcons,
numIcons);
{$IFOPT R+}
{$DEFINE CKRANGE}
{$R-}
{$ENDIF}
for i := 0 to (NumIcons - 1) do begin
DrawIcon(Form1.Canvas.Hand
i * LargeIconWidth,
0,
pTheLargeIcons^[i]);
TheIcon := TIcon. Create;
TheBitmap := TBitmap.Create;
TheIcon.Handle := pTheSmallIcons^[i];
TheBitmap.Width := TheIcon.Width;
TheBitmap.Height := TheIcon.Height;
TheBitmap.Canvas.Draw(0, 0, TheIcon);
TheIcon.Free;
Form1.Canvas.StretchDraw(R
100,
(i + 1) * SmallIconWidth,
100 + SmallIconHeight),
TheBitmap);
TheBitmap.Free;
end;
{$IFDEF CKRANGE}
{$UNDEF CKRANGE}
{$R+}
{$ENDIF}
FreeMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
FreeMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
end;
end;
end.
ASKER
I'll have a go and come back.
Ta.
Ta.
It's possible during runtime, too. Probably you would have to use SetClassLong(GCL_HICON, ...). But the problem is: You have to call this API from inside notepad. That again means you have to inject a little DLL into notepad's process, then in this DLL you can call SetClassLong. Injecting can be done e.g. by misusing SetWindowsHookEx. Quite difficult stuff.
Regards, Madshi.
Regards, Madshi.
ASKER
Could you do us a favour and cut that down to just extracting the 1st small icon? (I'm assuming that that's the one that you see on the taskbar.)
John.
John.
ASKER
Thanks Madshi but, woooooshhhh!!!! It went right over my head that did!
John.
John.
John,
Hmmm. Not sure if I can. It all depends on the EXE that you're trying to change - some don't have 16x16 icons and Windows scales the 32x32 one down.
The Neil
Hmmm. Not sure if I can. It all depends on the EXE that you're trying to change - some don't have 16x16 icons and Windows scales the 32x32 one down.
The Neil
ASKER
Would it be possible then to get both the 1st small and the 1st large? (If there is no small one then the large one is used!)
John.
John.
ASKER
Ignore that last pathetic comment I made! I've just done that myself.
John.
John.
ASKER
Neil : Okay then, can you do me a little example of a prog that returns the size and location of the TaskBar icon within an EXE? If you do this for me, I'll bump the points up to 400 and grade it Excellent so they bump up even more. Would you do that for us?
John.
John.
No can do I'm afraid. Inside the EXE can be several icons and ExtractIconsEx will get them all - it won't know which one is being used for the tray icon. I'll have a think and see what I can come up (no promises)
Wouldn't have minded those points either...
The Neil =:(
Wouldn't have minded those points either...
The Neil =:(
ASKER
I don't actually mean the tray icon - I mean the Task Manager icon (Alt+Tab icon). That'd be the 1st biggun wouldn't it?
John.
John.
I don't think it has to be the first one. It depends on what the application gives into the API "RegisterClass". It may be the first icon from the resources, it may be the last icon from the resources, it may even be an external ico file or something completely different... :-(
Sorry for posting such sad infos.
Regards, Madshi.
Sorry for posting such sad infos.
Regards, Madshi.
ASKER
Madshi - are you saying that it's not possible unless you go down that nasty path that you mentioned earlier? (Something about Captain Hook.)
John.
John.
Well, I'm not 100% sure, but I guess so... :-(
ASKER
Damn it!
I'll leave the question here till tomorrow and then delete it if there's no reasonable answer.
Thanks anyway everyone.
John.
I'll leave the question here till tomorrow and then delete it if there's no reasonable answer.
Thanks anyway everyone.
John.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Neil, you are a beauty!!!
If this program makes me smile, I'll give you the points I referred to previously!
My email is....
JayMol@Pu-Nani.co.uk
That's due to the fact that when I'm not programming, I just Looooove to ride it!
Thanks,
John.
If this program makes me smile, I'll give you the points I referred to previously!
My email is....
JayMol@Pu-Nani.co.uk
That's due to the fact that when I'm not programming, I just Looooove to ride it!
Thanks,
John.
Hey The Neil, this sounds interesting! Would you mind sending me this program, too? That would be kind... :O)
madshi@gmx.net
madshi@gmx.net
ASKER
BANDWAGON!!!!
ASKER
Adjusted points from 150 to 400
ASKER
Thanks for your help Neil. As I said, here's your points. (I am a man of my word!)
Thanks again.
John.
Thanks again.
John.
Do you mean the stupid thing actually worked? I am quite amazed seeing as I wrote this way back in the dim distant past when I was remotely intelligent (unlike now when I'm just brain dead). There are probably loads of ways to optimise it and if you do then I'd appreciate an updated version
It works, it works... <stunned disbelief>
The Neil =:0
It works, it works... <stunned disbelief>
The Neil =:0
ASKER
If I do stuff, I'll keep you posted mate.
Thanks again Neil,
John.
Thanks again Neil,
John.
TheNeil
your example is wrong.
give me
delphi2000@soim.com
your example is wrong.
give me
delphi2000@soim.com
TheNeil or Jaymol, I have purchased this question and have found out that the answer I was looking for was sent through e-mail. Would you be so kind as to send me the Project. I would really appreciate it. My e-mail address is syndromecrew@yahoo.com. Thank you!
ASKER
Neil, can you sort this out for him?
John.
John.
I'll have a hunt around and find the ZIP. Give me a couple of days though as this will be archived away somewhere (and I don't know where)
The Neil =:)
The Neil =:)
ASKER
Same here, or I'd send it now.
If you don't find it, let me know and I'll see what I can do.
John.
If you don't find it, let me know and I'll see what I can do.
John.
It's lost? Please help me. Thanks!
Jaymol or The Neil, why doesn't BinaryReplace.exe seem to work? I have tried it several times and it always says the same error message over and over: "Data could not be located. No changes have been made." Please help! Thanks!
Hey The Neil, this sounds great! Would you mind sending me this program, too? That would be kind... :O)
ashraf@al-waha.net
ashraf@al-waha.net
Search through the exe at a byte level and replace the icon data with a new one. Sadly you have to do it before the exe starts, and it's permanent - looks pretty though
The Neil =;)