Another program icon via command line

New to FreeBASIC? Post your questions here.
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Another program icon via command line

Post by St_W »

@jj2007: LoadIcon(0, IDI_APPLICATION) references a system-provided icon, there are also others. Of course when you want to reference a custom icon in your application's resources you have to pass the correct module handle. You shouldn't use the predefined value "IDI_APPLICATION" in that case, however.

As far as the OP told us he wants to modify the icon displayed by Explorer. So he wants an application that modifies its own embedded resources - without rebuilding the application from source.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Post by jj2007 »

St_W wrote:@jj2007: LoadIcon(0, IDI_APPLICATION) references a system-provided icon, there are also others.
Loading IDI_APPLICATION has no effect. It works with the other predefined ones, though.
You shouldn't use the predefined value "IDI_APPLICATION" in that case, however.
You can use whatever value below 65536.
So he wants an application that modifies its own embedded resources - without rebuilding the application from source.
That won't work. He must learn to rebuild the application (which is actually not that difficult).
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Post by newbieforever »

...
Still too busy to study the discussion...
My question (which seemed completely clear to me at first) still seems to be unclear. Can the following eliminate ambiguity?

MyProgram.exe is my FB-compiled program. It is a launcher program used to launch another programs, flexibly in the following way: If I rename MyProgram.exe to ProgA.exe, it will launch the program tmp\ProgASomething.exe; If I rename it to ProgB.exe, it will launch the program tmp\ProgBSomething.exe. (This is just for illustration, my real setting is more meaningful than it is recognizable here.)

What want is to add to MyProgram.exe (by an included code) the option: 'MyProgram.exe /icon:AnotherIcon.ico'. With this CL no program should be launched, only the program icon of MyProgram.exe (as shown in Windows Explorer) should be changed.

By this way I would be able to change the icon of MyProgram.exe to the icon of tmp\ProgA.exe etc. After renaming MyProgram.exe to ProgA.exe, on the icon of this launcher ProgA.exe would be recognizable which program will be launched.

As stated in my OP: My ultimate wish would be an additional option to return to the default icon (applied when compiling) via
MyProgram.exe /icon
(or at least to return to no specific icon).
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Post by jj2007 »

newbieforever wrote:What want is to add to MyProgram.exe (by an included code) the option: 'MyProgram.exe /icon:AnotherIcon.ico'. With this CL no program should be launched, only the program icon of MyProgram.exe (as shown in Windows Explorer) should be changed.
This is simply not possible! Explorer checks inside your executable which icon is provided in the resource section; it then extracts the icon and uses it to decorate the name of your file in its listview.

The commandline has a meaning for your program.exe but not for Explorer.

What you can do, however, is write a batch file that compiles your launcher with the needed resources including the executables that you want to launch, and the icon. This is not difficult at all, especially since you will have to compile anyway a new launcher for every set of executables.
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Post by newbieforever »

jj2007: What else can I do to eradicate these misconceptions???

"... the program icon of MyProgram.exe (as shown in Windows Explorer) should be changed" means, of course, that the icon in the resource section should be changed!

I am doing this with my AHK-compiled programs all the time: When I run my program Prog.exe with 'Prog.exe /icon:Another.ico', it copies itself to ProgCopy.exe and replaces the icon in the resource section of ProgCopy.exe by Another.ico.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Another program icon via command line

Post by MrSwiss »

newbieforever wrote:I am doing this with my AHK-compiled programs all the time: When I run my program Prog.exe with 'Prog.exe /icon:Another.ico', it copies itself to ProgCopy.exe and replaces the icon in the resource section of ProgCopy.exe by Another.ico.
I think, that I've figured it out now, it appears that:

AHK-compiled (source + JIT-Compiler) <> FBC-compiled (binary executable)

It seems that AHK isn't a truely compiled *binary* but, the source bundled with
a JIT-compiler (started, then reading source and compiling it, then executing it).
This whould also explain the *massive* sizes, of AHK.exe's.
(Because it always contains the Compiler itself.)
Last edited by MrSwiss on Jul 08, 2018 22:28, edited 1 time in total.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Another program icon via command line

Post by Josep Roca »

Is it possible to do it?: Yes.

Are you going to find somebody that does the job for you?: Doubtful.

See this article in CodeProject if you want to learn how to do it:

Replacing ICON resources in EXE and DLL files
https://www.codeproject.com/Articles/30 ... -DLL-files
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Another program icon via command line

Post by grindstone »

To get the "file-association-icon", look at SHGetFileInfo
https://docs.microsoft.com/de-de/window ... tfileinfoa

To get the default-Icon of the EXE, look at ExtractIconEx (index 0)
https://docs.microsoft.com/de-de/window ... acticonexa
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Post by jj2007 »

newbieforever wrote:jj2007: What else can I do to eradicate these misconceptions???
Correct me if I am wrong. You want to:
- create an executable called "Launcher.exe"
- which has inside one or more executables
- the launcher is supposed to extract them, and to launch them
- Launcher.exe should have a specific icon
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Post by newbieforever »

It seems not to be easy to compose such an icon-replacing code in FB (for a newbie like me)...

For AutoHotkey there is a ReplaceIcon() function which is used to replace the icon of compiled AHK scripts. I found out that this function obviously can be adapted easily to be able to replace the icon of (maybe) EVERY executable. It works with FB-compiled executables too. Maybe this script might be a suggestion for someone here how to do it in FB.


@Josep Roca: "Are you going to find somebody that does the job for you?: Doubtful."
It wouldn't be for me,
it would be for the community.

;-)

Code: Select all

; THIS IS AN AUTOHOTKEY SCRIPT

SetWorkingDir, %A_ScriptDir%

ExeFil := "AnExe.exe"
IcoFil := "AnIco.ico"

ReplaceIcon(ExeFil, IcoFil) 

; ============================================================================
ReplaceIcon(ExeFil, IcoFil)
{
  Global _EI_HighestIconID
  Static IconID := 159

  Module := DllCall("BeginUpdateResource", "str", ExeFil, "uint", 0, "ptr")

  ids := EnumIcons(ExeFil, IconID)
  If !IsObject(ids)
    Return false

  f := FileOpen(IcoFil, "r")
  If !IsObject(f)
    Return false

  VarSetCapacity(igh, 8), f.RawRead(igh, 6)
  If (NumGet(igh, 0, "UShort") != 0) || (NumGet(igh, 2, "UShort") != 1)
    Return false

  wCount := NumGet(igh, 4, "UShort")

  VarSetCapacity(rsrcIconGroup, rsrcIconGroupSize := 6 + wCount*14)
  NumPut(NumGet(igh, "Int64"), rsrcIconGroup, "Int64") ; fast copy

  ige := &rsrcIconGroup + 6

  ; Delete all the images
  Loop, % ids.MaxIndex()
    DllCall("UpdateResource", "ptr", Module, "ptr", 3, "ptr", ids[A_Index], "ushort"
            , 0x409, "ptr", 0, "uint", 0, "uint")

  Loop, %wCount%
  {
    thisID := ids[A_Index]
    If !thisID
      thisID := ++ _EI_HighestIconID

    f.RawRead(ige+0, 12) ; read all but the offset
    NumPut(thisID, ige+12, "UShort")

    imgOffset := f.ReadUInt()
    oldPos := f.Pos
    f.Pos := imgOffset

    VarSetCapacity(iconData, iconDataSize := NumGet(ige+8, "UInt"))
    f.RawRead(iconData, iconDataSize)
    f.Pos := oldPos

    DllCall("UpdateResource", "ptr", Module, "ptr", 3, "ptr", thisID, "ushort"
            , 0x409, "ptr", &iconData, "uint", iconDataSize, "uint")

    ige += 14
  }

  DllCall("UpdateResource", "ptr", Module, "ptr", 14, "ptr", IconID, "ushort"
         , 0x409, "ptr", &rsrcIconGroup, "uint", rsrcIconGroupSize, "uint")
      
  DllCall("EndUpdateResource", "ptr", Module, "uint", 0)
}

EnumIcons(ExeFil, IconID)
{
  ; RT_GROUP_ICON = 14
  ; RT_ICON = 3
  Global _EI_HighestIconID
  Static pEnumFunc := RegisterCallback("EnumIcons_Enum")

  hModule := DllCall("LoadLibraryEx", "str", ExeFil, "ptr", 0, "ptr", 2, "ptr")
  If !hModule
    Return

  _EI_HighestIconID := 0
; ***
; If the following section is removed, ReplaceIcon() seems to work with
; EVERY executable (not only with AutoHotkey.exe or AutoHotkeySC.bin)!!!
; ======================================================================
/*
  If DllCall("EnumResourceNames", "ptr", hModule, "ptr", 3, "ptr", pEnumFunc, "uint", 0) = 0
  {
    DllCall("FreeLibrary", "ptr", hModule)
    Return
  }
*/

  hRsrc := DllCall("FindResource", "ptr", hModule, "ptr", IconID, "ptr", 14, "ptr")
  hMem := DllCall("LoadResource", "ptr", hModule, "ptr", hRsrc, "ptr")
  pDirHeader := DllCall("LockResource", "ptr", hMem, "ptr")
  pResDir := pDirHeader + 6

  wCount := NumGet(pDirHeader+4, "UShort")
  iconIDs := []

  Loop, %wCount%
  {
    pResDirEntry := pResDir + (A_Index-1)*14
    iconIDs[A_Index] := NumGet(pResDirEntry+12, "UShort")
  }

  DllCall("FreeLibrary", "ptr", hModule)
  Return iconIDs
}

EnumIcons_Enum(hModule, Type, Name, lParam)
{
  Global _EI_HighestIconID
  If (Name < 0x10000) && (Name > _EI_HighestIconID)
   _EI_HighestIconID := Name
  Return 1
}
Last edited by newbieforever on Jul 09, 2018 9:59, edited 2 times in total.
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Another program icon via command line

Post by UEZ »

Well, why are you not using Resource Hacker? -> http://www.angusj.com/resourcehacker/
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Another program icon via command line

Post by counting_pine »

This may be a silly question, but is the icon (or at least the bitmap data for each size) stored in "cleartext" in the exe file, such that you can change the icon just by writing the icon data to the right area of the file?
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Post by newbieforever »

@counting_pine: The icon is an external normal ico file.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Post by jj2007 »

What I find pretty odd is that OP doesn't want to rebuild the launcher with the ico file embedded as a resource. That is by far the simplest solution, and the only reason not to do that is not having access to the source...
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Post by newbieforever »

jj2007: If rebuild means compile with fbc: That is impossible in my setting, the launcher should be used flexibly and no big fbc should be required to use it.


Is my explanation in viewtopic.php?f=2&t=26857&start=30#p249265 still a mistery???
Post Reply