Recent

Author Topic: Trying to do a resource update for icons and I'm nearly there ...  (Read 9346 times)

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
I have become enlightened. Will either update, or this is the best prank ever on the next person who googles this topic. Or I died of a heart attack.

ETA: my solution is in post #14, in return be nice to someone today.
« Last Edit: May 03, 2021, 10:12:52 pm by Spoonhorse »

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #1 on: April 30, 2021, 09:45:18 pm »
P.S. it looks like whoever wrote this understands the whole thing perfectly so maybe I'll re-use their code. I'd like to understand it better though.

https://stackoverflow.com/questions/35189283/change-icon-of-application-on-runtime

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #2 on: April 30, 2021, 11:18:34 pm »
Why are you doing it in the most complicated way? The easiest way is to open the project options ("Project" > "Project Options" > "Application") and to load the icon by using the "Load Icon" button. Then Lazarus takes care of everything.

Or do you want to replace the icon while the program is running? In this case, you simply can set "Application.Icon := OtherIcon", or in more detail:

Code: Pascal  [Select][+][-]
  1. type
  2.   TForm1 = class(TForm)
  3.     Button1: TButton;
  4.     procedure Button1Click(Sender: TObject);
  5.     procedure FormCreate(Sender: TObject);
  6.     procedure FormDestroy(Sender: TObject);
  7.   private
  8.     OtherIcon: TIcon;
  9.  
  10.   public
  11.  
  12.   end;
  13.  
  14. var
  15.   Form1: TForm1;
  16.  
  17. implementation
  18.  
  19. {$R *.lfm}
  20.  
  21. { TForm1 }
  22.  
  23. procedure TForm1.Button1Click(Sender: TObject);
  24. begin
  25.   Application.Icon := OtherIcon;
  26. end;
  27.  
  28. procedure TForm1.FormCreate(Sender: TObject);
  29. begin
  30.   OtherIcon := TIcon.Create;
  31.   OtherIcon.LoadFromFile('C:\Lazarus\lazarus-trunk_fpc-3.2.0\images\icons\brown.ico');
  32.   // or load an icon from resource
  33. end;
  34.  
  35. procedure TForm1.FormDestroy(Sender: TObject);
  36. begin
  37.   OtherIcon.Free;
  38. end;  

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #3 on: May 01, 2021, 03:06:06 am »
Thank you for the advice, wp, but what if I do not have access to the source code of executable.exe? What if it is not written in Pascal?

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #4 on: May 01, 2021, 05:38:00 pm »
The trouble with the code I found on Stack Overflow is that the guy's copying it from one .exe file to another rather than from an .ico file and that's no good to me.

Here's a fresh version of my code. It is now even closer, if I look at the updated version in Resource Hacker it tells me that the group has nine icons, which is true, that they're 16.8 million color, which is true, that they're all 16 x 16, which is not true, and that it can't actually show me what they look like, which is annoying. And that they all have the ordinal name 150.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var   vResHandle: THandle;
  3.       MyIcon: TMemoryStream;
  4. begin
  5.   // Get the icon.
  6.   MyIcon := TMemoryStream.Create;
  7.   MyIcon.LoadFromFile('icon.ico');
  8.   // Set the position in the memory stream to the start.
  9.   MyIcon.Seek(0, soFromBeginning);
  10.  
  11.   // Get the handle.
  12.   vResHandle := BeginUpdateResource('exec.exe', False);
  13.   if vResHandle=0 then
  14.     raise Exception.Create('System giving error message: '
  15.                            + SysErrorMessage(GetLastError));
  16.     try
  17.     // Change the icon.
  18.     if not UpdateResource(vResHandle
  19.                           , RT_GROUP_ICON
  20.                           , PChar('MAINICON')
  21.                           , LANG_NEUTRAL
  22.                           , MyIcon.Memory
  23.                           , MyIcon.Size)
  24.     then
  25.       raise Exception.Create('System giving error message: '
  26.                              + SysErrorMessage(GetLastError));
  27.     finally
  28.     EndUpdateResource(vResHandle, False);
  29.     end;
  30.   MyIcon.Free;
  31. end;  
« Last Edit: May 01, 2021, 05:40:40 pm by Spoonhorse »

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #5 on: May 01, 2021, 06:26:45 pm »
but what if I do not have access to the source code of executable.exe? What if it is not written in Pascal?

Did you not know it is a Pascal forum?
Did you trying to do some hacking?
Did you not know it is not appropriate to discuss something illegal in this forum?
 >:D

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #6 on: May 01, 2021, 06:36:22 pm »
but what if I do not have access to the source code of executable.exe? What if it is not written in Pascal?

Did you not know it is a Pascal forum?
Did you trying to do some hacking?
Did you not know it is not appropriate to discuss something illegal in this forum?
 >:D

Calm down. Changing the icon of an executable is not a crime.

You can do it with any command line tool. Its useful when you have to customize a binary, say for example Electron, that comes with his own icon and you need to change it when distributing your app.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #7 on: May 01, 2021, 06:59:00 pm »
What if it is not written in Pascal?

If it is not written in Lazarus/Freepascal, then it is off-topic.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #8 on: May 01, 2021, 07:06:06 pm »
What if it is not written in Pascal?
If it is not written in Lazarus/Freepascal, then it is off-topic.

Why off-topic? He's asking how to build an icon-changer in Pascal, like Resource Hacker (a Delphi app) can do (IIRC). The "not source, not in Pascal" is, essentially, just his target "data".
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #9 on: May 01, 2021, 07:23:21 pm »
Changing the icon of an executable is not a crime.

I am not a student of criminology but I what know is if someone change the icon of my program without my permission, I won't happy.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #10 on: May 01, 2021, 07:40:12 pm »
Changing the icon of an executable is not a crime.

I am not a student of criminology but I what know is if someone change the icon of my program without my permission, I won't happy.

We don't know what executable. For all we know it may be public domain, but without source, or he hasn't got the toolchain to build it himself.

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #11 on: May 01, 2021, 08:10:15 pm »
Hi.

(1) I think I know how to do this now, I have found my fundamental error. I need to take the icon file, split it into two parts and inject them into two different places.

(2) Changing the Application.Icon only changes the thing in the top left hand corner of your form. It doesn't change how it displays on the taskbar.

(3) If I wanted to do this for illegal purposes I could do it with Resource Hacker which I have downloaded. I want to give my users the capacity to do this. This is the only reason why anyone would want to do this in code.

(4) Guys, calm down. What crime could I commit and actually get away with through changing the icon? All the copyright information would still be there. In fact, I'm trying to do the exact opposite if anything — I've written a free program so customizable that the last step is to give it a new name and logo and publisher name and then even sell it for commercial purposes if you can find a buyer. Or give it away free, like decent people. I'm trying to give people every facility to do that. But because of point (2), in order for my program to do that for them I have to know how to do this. So far as I can see the only sensible way is to copy the .exe file of my program under a different name and do this. I have thought of one dumb way that increase the size of my setup.exe by orders of magnitude, one fairly sensible way which puts my users to mild inconvenience, one almost-sensible way which I have no idea how to start to implement, and one totally successful but incredibly lazy way which is also illegal, so I'm going with this one.
« Last Edit: May 01, 2021, 08:42:49 pm by Spoonhorse »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #12 on: May 02, 2021, 02:20:41 pm »
Changing the icon of an executable is not a crime.

I am not a student of criminology but I what know is if someone change the icon of my program without my permission, I won't happy.

I've used similar approaches in the past to change the boot icon of Windows XP (which required to modify a resource in the ntoskrnl.exe).

And even if I'd change the icon of your program on my computer what would you care if I wouldn't distribute it? Also I wouldn't even have to write my own software, cause I could just use one existing resource hacker software to do that.

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #13 on: May 02, 2021, 08:50:12 pm »
Changing the icon of an executable is not a crime.

I am not a student of criminology but I what know is if someone change the icon of my program without my permission, I won't happy.

I've used similar approaches in the past to change the boot icon of Windows XP (which required to modify a resource in the ntoskrnl.exe).

And even if I'd change the icon of your program on my computer what would you care if I wouldn't distribute it? Also I wouldn't even have to write my own software, cause I could just use one existing resource hacker software to do that.

Everyone did that in that times =) Customizing Windows XP. Even there was a time when you can add Windows Vista style to Windows XP changing the msstyles and explorer icons, all "hacking" system files exe or dll.

Spoonhorse

  • Full Member
  • ***
  • Posts: 123
Re: Trying to do a resource update for icons and I'm nearly there ...
« Reply #14 on: May 03, 2021, 01:27:37 pm »
OK people! The following is working code, don't do bad crimes with it! You'll need to put Windows in your uses statement.

Some notes on what effects it has on the application and Windows, because some of this is subtle.

(1) Although the application icon (in the top left corner of your main form) can be set to be completely different from the main icon for the program, it seems like it's overwritten to be in line with the main icon once you do the update. 99% of the time this would be exactly what you want. If it isn't what you want you'll have to take it from here.

(2) File Explorer caches this stuff so hard that you won't see any change in how the icon's displayed there unless you restart Explorer. This is fine for my purposes, if it's a problem for you then again you'll have to solve it yourself, sorry.

(3) This is NOT an answer to that frequently-asked question, "how do I change the toolbar icon of my Pascal-based application while it's running?" Because you can't do a resource update on an executable that's being executed, whether your own or another. What you could do, if you really must, is have your program save all its data and then shut down after starting a program which waits for it to shut down, changes its icon, and then starts it back up, at which point it reloads its data. This would work, but it would take time of course, you couldn't use it for something you'd want to change frequently like to indicate the status of the program.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var   vResHandle: THandle;
  3.       MyIcon: TMemoryStream;
  4.       i,j: integer;
  5.       s: string;
  6.       ImageCount: Word;
  7.       ImageSize: DWord;
  8.       ab, m: TMemoryStream;
  9.  
  10. const HeaderSize = 6;
  11.       IcoEntrySize = 16;
  12.       ResEntrySize = 14;
  13.  
  14. begin
  15.  
  16. // Short explanation. An icon file consists of (a) a six-byte header which
  17. // includes among other things information about how many icons are in
  18. // the file; (b) sixteen bytes of metadata for each icon; (c) the icons.
  19.  
  20. // But that's how icons are stored as files. As executable resources,
  21. // Windows considers that (a) and (b) are one resource but (c) is a different
  22. // resource, indeed one resource for each image, so we have to split the icon
  23. // file up and do several resource updates.
  24.  
  25. // It also requires only fourteen bytes of metadata per entry: instead of the
  26. // last parameter being a double word referring to the position of the image
  27. // in memory, it's a single word conferring an ID.
  28.  
  29. // Initialize stuff
  30. MyIcon := TMemoryStream.Create;
  31. ab := TMemoryStream.Create;
  32. m := TMemoryStream.Create;
  33.  
  34. // Get the icon
  35. MyIcon.LoadFromFile('icon.ico');
  36.  
  37. // Get the handle for the resource update..
  38. vResHandle := BeginUpdateResource('test.exe', False);
  39.  
  40. // We skip forward in the memory stream to where Windows keeps the image count and read it.
  41. MyIcon.Seek(4,soFromBeginning);
  42. ImageCount:=MyIcon.ReadWord;
  43.  
  44. // Go back to the beginning ...
  45. MyIcon.Seek(0,soFromBeginning);
  46.  
  47. // We read the directory information into ab, modifying its format as we do so.
  48.  
  49. for j:=1 to HeaderSize do ab.WriteByte(MyIcon.ReadByte);
  50.     for i:=1 to ImageCount do
  51.         begin
  52.         for j:=1 to IcoEntrySize - 4 do ab.WriteByte(MyIcon.ReadByte);
  53.         MyIcon.ReadDWord;  // To skip over it.
  54.         ab.WriteWord(i);
  55.         end;
  56.  
  57. // Update the icon directory with ab, which is now in the correct format.
  58.  
  59. UpdateResource(vResHandle
  60.                       , RT_GROUP_ICON
  61.                       , PChar('MAINICON')
  62.                       , LANG_NEUTRAL
  63.                       , ab.Memory
  64.                       , ab.Size);
  65.  
  66. // Now the size of each icon is contained as a double word in the directory
  67. // entries for each item, so we use that to cut the remainder of the memory
  68. // stream into chunks and update them one at a time.
  69.  
  70. for i := 1 to ImageCount do
  71.     begin
  72.     m := TMemoryStream.Create;
  73.     ab.Seek(HeaderSize+(i-1)*ResEntrySize+8,soFromBeginning);
  74.     ImageSize:=ab.ReadDWord;
  75.     for j:=1 to ImageSize do m.WriteByte(MyIcon.ReadByte);
  76.     UpdateResource(vResHandle
  77.                   , RT_ICON
  78.                   , MAKEINTRESOURCE(i)
  79.                   , LANG_NEUTRAL
  80.                   , m.Memory
  81.                   , m.Size);
  82.     m.Free;
  83.     end;
  84.  
  85. EndUpDateResource(vResHandle,False);
  86. MyIcon.Free;
  87. ab.Free;
  88. end;
« Last Edit: May 04, 2021, 10:44:49 am by Spoonhorse »

 

TinyPortal © 2005-2018