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.
LVL 6
JaymolAsked:
Who is Participating?
 
TheNeilCommented:
John,

I have the source for an app I wrote a few years ago that rips through an EXE and can modify the icon (and any other string of data actually). Give me your email and I'll send it through (if you want it)

The Neil =;)
0
 
TheNeilCommented:
There is a nasty way to do this...

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 =;)
0
 
JaymolAuthor Commented:
Is that the only way of doing it Neil?  (Do you know?)

John.
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
JaymolAuthor Commented:
Also, is the icon always in the same location, or is there a particular way of locating it in the exe?

John.
0
 
jeurkCommented:
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...
0
 
JaymolAuthor Commented:
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.
0
 
TheNeilCommented:
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
0
 
JaymolAuthor Commented:
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.
0
 
TheNeilCommented:
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_CXSMICON);
    SmallIconHeight := GetSystemMetrics(SM_CYSMICON);
    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.Handle,
               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(Rect(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.
0
 
JaymolAuthor Commented:
I'll have a go and come back.

Ta.
0
 
MadshiCommented:
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.
0
 
JaymolAuthor Commented:
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.
0
 
JaymolAuthor Commented:
Thanks Madshi but, woooooshhhh!!!! It went right over my head that did!

John.
0
 
TheNeilCommented:
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
0
 
JaymolAuthor Commented:
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.
0
 
JaymolAuthor Commented:
Ignore that last pathetic comment I made!  I've just done that myself.

John.
0
 
JaymolAuthor Commented:
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.
0
 
TheNeilCommented:
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 =:(
0
 
JaymolAuthor Commented:
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.
0
 
MadshiCommented:
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.
0
 
JaymolAuthor Commented:
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.
0
 
MadshiCommented:
Well, I'm not 100% sure, but I guess so...   :-(
0
 
JaymolAuthor Commented:
Damn it!

I'll leave the question here till tomorrow and then delete it if there's no reasonable answer.

Thanks anyway everyone.

John.
0
 
JaymolAuthor Commented:
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.
0
 
MadshiCommented:
Hey The Neil, this sounds interesting! Would you mind sending me this program, too? That would be kind...    :O)

madshi@gmx.net
0
 
JaymolAuthor Commented:
BANDWAGON!!!!
0
 
JaymolAuthor Commented:
Adjusted points from 150 to 400
0
 
JaymolAuthor Commented:
Thanks for your help Neil.  As I said, here's your points.  (I am a man of my word!)

Thanks again.

John.
0
 
TheNeilCommented:
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
0
 
JaymolAuthor Commented:
If I do stuff, I'll keep you posted mate.

Thanks again Neil,

John.
0
 
lingxinCommented:
TheNeil
your example is wrong.
give me
delphi2000@soim.com
0
 
New2DelphiCommented:
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!
0
 
JaymolAuthor Commented:
Neil, can you sort this out for him?

John.
0
 
TheNeilCommented:
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 =:)
0
 
JaymolAuthor Commented:
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.
0
 
New2DelphiCommented:
It's lost? Please help me. Thanks!
0
 
New2DelphiCommented:
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!
0
 
ashrafsalahCommented:
Hey The Neil, this sounds great! Would you mind sending me this program, too? That would be kind...    :O)

ashraf@al-waha.net
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.