Trying to do a resource update for icons and I'm nearly there ... lazarus / 67-Windows ---------------------------------------------------------------------- Spoonhorse · 2021-04-30 19:22 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. ---------------------------------------------------------------------- Spoonhorse · 2021-04-30 19:45 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 · 2021-04-30 21:18 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);  private    OtherIcon: TIcon;   public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);begin  Application.Icon := OtherIcon;end; procedure TForm1.FormCreate(Sender: TObject);begin  OtherIcon := TIcon.Create;  OtherIcon.LoadFromFile('C:\Lazarus\lazarus- trunk_fpc-3.2.0\images\icons\brown.ico');  // or load an icon from resourceend; procedure TForm1.FormDestroy(Sender: TObject);begin  OtherIcon.Free;end; ---------------------------------------------------------------------- Spoonhorse · 2021-05-01 01:06 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 · 2021-05-01 15:38 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var   vResHandle: THandle;      MyIcon: TMemoryStream;begin  // Get the icon.  MyIcon := TMemoryStream.Create;  MyIcon.LoadFromFile('icon.ico');  // Set the position in the memory stream to the start.  MyIcon.Seek(0, soFromBeginning);   // Get the handle.  vResHandle := BeginUpdateResource('exec.exe', False);  if vResHandle=0 then    raise Exception.Create('System giving error message: '                         + SysErrorMessage(GetLastError));    try    // Change the icon.  if not UpdateResource(vResHandle                          , RT_GROUP_ICON                          , PChar('MAINICON')                        , LANG_NEUTRAL                          , MyIcon.Memory                        , MyIcon.Size)    then      raise Exception.Create('System giving error message: '                           + SysErrorMessage(GetLastError));    finally    EndUpdateResource(vResHandle, False);    end;  MyIcon.Free;end; ---------------------------------------------------------------------- Handoko · 2021-05-01 16:26 Quote from: Spoonhorse on May 01, 2021, 03:06:06 am 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? ---------------------------------------------------------------------- lainz · 2021-05-01 16:36 Quote from: Handoko on May 01, 2021, 06:26:45 pmQuote from: Spoonhorse on May 01, 2021, 03:06:06 am 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? 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 · 2021-05-01 16:59 Quote from: Spoonhorse on May 01, 2021, 03:06:06 amWhat if it is not written in Pascal? If it is not written in Lazarus/Freepascal, then it is off-topic. ---------------------------------------------------------------------- lucamar · 2021-05-01 17:06 Quote from: marcov on May 01, 2021, 06:59:00 pmQuote from: Spoonhorse on May 01, 2021, 03:06:06 amWhat 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". ---------------------------------------------------------------------- Handoko · 2021-05-01 17:23 Quote from: lainz on May 01, 2021, 06:36:22 pmChanging 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 · 2021-05-01 17:40 Quote from: Handoko on May 01, 2021, 07:23:21 pmQuote from: lainz on May 01, 2021, 06:36:22 pmChanging 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 · 2021-05-01 18:10 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. ---------------------------------------------------------------------- PascalDragon · 2021-05-02 12:20 Quote from: Handoko on May 01, 2021, 07:23:21 pmQuote from: lainz on May 01, 2021, 06:36:22 pmChanging 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 · 2021-05-02 18:50 Quote from: PascalDragon on May 02, 2021, 02:20:41 pmQuote from: Handoko on May 01, 2021, 07:23:21 pmQuote from: lainz on May 01, 2021, 06:36:22 pmChanging 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 · 2021-05-03 11:27 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var   vResHandle: THandle;      MyIcon: TMemoryStream;      i,j: integer;      s: string;      ImageCount: Word;      ImageSize: DWord;      ab, m: TMemoryStream; const HeaderSize = 6;      IcoEntrySize = 16;      ResEntrySize = 14; begin // Short explanation. An icon file consists of (a) a six-byte header which// includes among other things information about how many icons are in// the file; (b) sixteen bytes of metadata for each icon; (c) the icons. // But that's how icons are stored as files. As executable resources,// Windows considers that (a) and (b) are one resource but (c) is a different// resource, indeed one resource for each image, so we have to split the icon// file up and do several resource updates. // It also requires only fourteen bytes of metadata per entry: instead of the// last parameter being a double word referring to the position of the image// in memory, it's a single word conferring an ID. // Initialize stuffMyIcon := TMemoryStream.Create;ab := TMemoryStream.Create;m := TMemoryStream.Create; // Get the iconMyIcon.LoadFromFile('icon.ico'); // Get the handle for the resource update..vResHandle := BeginUpdateResource('test.exe', False); // We skip forward in the memory stream to where Windows keeps the image count and read it.MyIcon.Seek(4,soFromBeginning);ImageCount:=MyIcon.ReadWord; // Go back to the beginning ...MyIcon.Seek(0,soFromBeginning); // We read the directory information into ab, modifying its format as we do so. for j:=1 to HeaderSize do ab.WriteByte(MyIcon.ReadByte);    for i:=1 to ImageCount do        begin        for j:=1 to IcoEntrySize - 4 do ab.WriteByte(MyIcon.ReadByte);        MyIcon.ReadDWord;  // To skip over it.        ab.WriteWord(i);        end; // Update the icon directory with ab, which is now in the correct format. UpdateResource(vResHandle                      , RT_GROUP_ICON                      , PChar('MAINICON')                    , LANG_NEUTRAL                      , ab.Memory                    , ab.Size); // Now the size of each icon is contained as a double word in the directory// entries for each item, so we use that to cut the remainder of the memory// stream into chunks and update them one at a time. for i := 1 to ImageCount do    begin    m := TMemoryStream.Create;    ab.Seek(HeaderSize+(i-1)*ResEntrySize+8,soFromBeginning);    ImageSize:=ab.ReadDWord;    for j:=1 to ImageSize do m.WriteByte(MyIcon.ReadByte);    UpdateResource(vResHandle                , RT_ICON                  , MAKEINTRESOURCE(i)                  , LANG_NEUTRAL                  , m.Memory                  , m.Size);    m.Free;    end; EndUpDateResource(vResHandle,False);MyIcon.Free;ab.Free;end; ---------------------------------------------------------------------- marcov · 2021-05-03 12:58 Thanks reporting back despite the pushback (and mea culpa me there too) ---------------------------------------------------------------------- Spoonhorse · 2021-05-03 20:11 The pushback made me more likely to come back and gloat. I have achieved the forbidden magics! Woe unto the unbelievers.