Another program icon via command line

New to FreeBASIC? Post your questions here.
newbieforever
Posts: 84
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Postby newbieforever » Jul 07, 2018 17:13

And the truth is, we're a bunch of weird nerds. Not true?!
UEZ
Posts: 213
Joined: May 05, 2017 19:59
Location: Germany

Re: Another program icon via command line

Postby UEZ » Jul 07, 2018 19:06

Back to op's question:

Here a working version for Windows OS:

Code: Select all

'coded by UEZ
'Usage _WinAPI_SetWindowTitleIcon.exe /icon:email-logo.ico

#include "file.bi"
#Ifdef __Fb_64bit__
   #Inclib "gdiplus"
   #Include Once "win/gdiplus-c.bi"
#Else
   #Include Once "win/gdiplus.bi"
   Using gdiplus
#Endif

Declare Function WndProc(hWnd As HWND, uMsg As UINT, wParam As WPARAM, lParam As LPARAM) As Integer
Declare Function _WinAPI_SetWindowTitleIcon(sFile As String, hHWND As Any Ptr) As Byte

'check command line paramter
Dim As String CmdLineParameter
Dim As Ubyte iPos, bFile = False
iPos = Instr(Command(1), "/icon:")
If iPos = 1 Then
   CmdLineParameter = Mid(Command(1), 7)
   If FileExists(CmdLineParameter) <> 0 Then bFile = TRUE
EndIf


'create a test GUI
Dim wc As WNDCLASSEX
Dim msg As MSG
Dim hHWND As HWND
Dim As Integer sW, sH
ScreenInfo(sW, sH)

Dim szAppName As ZString * 30 => "FB GUI"
Dim As String sTitle = "<- Icon ;-)"
Dim Shared As ULong iW, iH
iW = 300
iH = 200


With wc
   .style         = CS_HREDRAW Or CS_VREDRAW
   .lpfnWndProc   = @WndProc
   .cbClsExtra    = NULL
   .cbWndExtra    = NULL
   .hInstance     = GetModuleHandle(NULL)
   .hIcon         = LoadIcon(NULL, IDI_APPLICATION )
   .hCursor       = LoadCursor(NULL, IDC_ARROW )
   .hbrBackground = GetStockObject(WHITE_BRUSH )
   .lpszMenuName  = NULL
   .lpszClassName = @szAppName
   .cbSize         = SizeOf(WNDCLASSEX)
End With
 
RegisterClassEx(@wc)
hHWND = CreateWindowEx(0, wc.lpszClassName, sTitle, _
                       WS_OVERLAPPEDWINDOW Or WS_VISIBLE, _
                       (sW - iW) / 2, (sH - iH) / 2, _
                       iW, iH, _
                       NULL, NULL, wc.hInstance, NULL)
                  


'set icon to GUI
If bFile Then _WinAPI_SetWindowTitleIcon(CmdLineParameter, hHWND)

While GetMessage(@Msg, 0, 0, 0)
   TranslateMessage(@Msg)
   DispatchMessage(@Msg)
Wend

Function WndProc(hWnd As HWND,uMsg As UINT,wParam As WPARAM,lParam As LPARAM) As Integer
   Select Case uMsg
      Case WM_CLOSE
         PostQuitMessage(0)
      Case WM_CREATE
      
      Case Else
         Return DefWindowProc(hWnd, uMsg, wParam, lParam)
   End Select
End Function

Function _WinAPI_SetWindowTitleIcon(sFile As String, hHWND As Any Ptr) As Byte
   Dim gdipToken As ULONG_PTR
   Dim GDIp As GdiplusStartupInput
   GDIp.GdiplusVersion = 1
   If GdiplusStartup(@gdipToken, @GDIp, NULL) <> 0 Then Return -1
   Dim As any Ptr hImage, hImageScaled, hIcon
   If GdipLoadImageFromFile(Wstr(sFile), @hImage) <> 0 Then
      GdiplusShutdown(gdipToken)
      Return -2
   End If
   GdipCreateHICONFromBitmap(hImage, @hIcon)
   SendMessageW(hHWND, WM_SETICON, 1, Cast(LParam, hIcon))
   GdipDisposeImage(hImage)
   DestroyIcon(hIcon)
   GdiplusShutdown(gdipToken)
   Return 1
End Function


Compile it and start from command line: ThisExe.exe /icon:"path to the ico file" . You can load also GDI+ supported image files.


Tested on Windows 10 x64.
Last edited by UEZ on Jul 07, 2018 21:05, edited 1 time in total.
marcov
Posts: 2650
Joined: Jun 16, 2005 9:45
Location: Eindhoven, NL
Contact:

Re: Another program icon via command line

Postby marcov » Jul 07, 2018 20:03

newbieforever wrote:And the truth is, we're a bunch of weird nerds. Not true?!


The font joke is getting old
dodicat
Posts: 5355
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Another program icon via command line

Postby dodicat » Jul 07, 2018 20:54

Hello UEZ
Works perfectly on Win 10.
My icon size 128 X 128, which always works well with a freebasic rc file.
I bsaved a little image and re saved it as .ico.
The force awakens.
UEZ
Posts: 213
Joined: May 05, 2017 19:59
Location: Germany

Re: Another program icon via command line

Postby UEZ » Jul 07, 2018 21:01

dodicat wrote:Hello UEZ
Works perfectly on Win 10.
My icon size 128 X 128, which always works well with a freebasic rc file.
I bsaved a little image and re saved it as .ico.
The force awakens.


You can load your little image directly. ;-)

May the force be with you...
dodicat
Posts: 5355
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Another program icon via command line

Postby dodicat » Jul 07, 2018 22:06

This one is out of fashion now.

Code: Select all



Sub EURO(x As Integer,y As Integer,s As Single,im As Any Pointer=0)
    #macro pentagon(starx,stary,size,col)
    Scope
        Var count=0,rad=0.0,_px=0.0,_py=0.0
        For z As Single=0+.28 To 2*pi+.1+.28 Step 2*pi/10
            count=count+1
            If count Mod 2=0 Then rad=size Else rad=.4*size
            _px=starx+rad*Cos(z)
            _py=stary+rad*Sin(z)
            If count=1 Then Pset im,(_px,_py)Else Line im,-(_px,_py),col
        Next z
        Paint im,(starx,stary),col,col
    End Scope
    #endmacro
    Dim As Double pi=4*Atn(1)
    Dim As Integer lx=60*s,ly=1*lx
    Line im,(x,y)-(x+lx,y+ly),Rgb(2,3,192),bf
    Dim As Integer cntx=(x+x+lx)/2,cnty=(y+Y+ly)/2
    For z As Double=0 To 2*pi Step 2*pi/12
        Var px=cntx+.7*(lx/2)*Cos(z)
        Var py=cnty+.7*(lx/2)*Sin(z)
        pentagon(px,py,3*s,Rgb(243,236,24))
    Next z
End Sub

screen 19,32
dim as any ptr i=imagecreate(128,128)
euro(00,00,2.2,i)
put(50,50),i
print "Euro.ico is the icon"
bsave "euro.bmp",i
sleep 50
shell "rename euro.bmp euro.ico"

sleep


 
caseih
Posts: 1302
Joined: Feb 26, 2007 5:32

Re: Another program icon via command line

Postby caseih » Jul 07, 2018 22:40

UEZ wrote:Back to op's question:
The OP is not being very clear about what he's trying to accomplish but it seems he wants to change the embedded icon in a third-party EXE using FB code. In other words, open the EXE, modify the icon, and save it back out. For example, take a binary and make it look to the uninitiated like a jpeg image file when viewed in Explorer. Of course hacking an EXE's embedded icon will not necessarily change the icon that's displayed in the window corner or the task bar, as those can be set programmatically by the EXE to anything it wants, regardless of the embedded default icon.

In any event, there are programs that will do this out there. I found at least one (with VB source code) with a simple Google search.

There are perhaps legitimate reasons why you'd want to hack the default icon of a third-party binary. newbieforever has never been very forthcoming with his goals here, and doesn't appear to have done much research before coming to the forum. It's unknown whether his projects are just for personal edification purposes (like most of us on the forum), or something else.

Or have I completely misread what newbieforever was trying to do?
jj2007
Posts: 945
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Postby jj2007 » Jul 08, 2018 7:11

caseih wrote:it seems he wants to change the embedded icon in a third-party EXE using FB code.
newbieforever wrote:How a FB program (MyProgram.exe) could be enabled (by its code) to change its icon via command line:
MyProgram.exe /icon:AnotherIcon.ico
A Windows GUI application loads the icon with LoadIcon(GetModuleHandle(0), IDI_APPLICATION)

The Hello World proggie in examples\GUI\win32\hello.bas does it with .hIcon = LoadIcon( NULL, IDI_APPLICATION ) - and consequently, the exe shows no icon (to be corrected...).

Back to OP's objective: If you want a different icon via the commandline, the easiest way would be to include a choice of icons in the resource file, and to use the ID passed via the commandline to pick the right one. Using IDI_APPLICATION is just a convention, any other ID will do.

If, however, you don't mind shipping the icon file with the application, you may use this:

Code: Select all

#include once "win\shellapi.bi"
dim lpiIcon as WORD = 0
.hIcon = ExtractAssociatedIcon(GetModuleHandle(0), "another.ico", @lpiIcon)
Of course, you need to supply the path using the commandline argument.

In contrast to the LoadIcon bug in the hello world proggie, .hIcon = ExtractAssociatedIcon(0, "some.ico", @lpiIcon) works, too (no GetModuleHandle needed), but this is not documented by Microsoft.

There is more documentation at MSDN.
PaulSquires
Posts: 715
Joined: Jul 14, 2005 23:41
Contact:

Re: Another program icon via command line

Postby PaulSquires » Jul 08, 2018 10:28

jj2007 wrote:A Windows GUI application loads the icon with LoadIcon(GetModuleHandle(0), IDI_APPLICATION)

The Hello World proggie in examples\GUI\win32\hello.bas does it with .hIcon = LoadIcon( NULL, IDI_APPLICATION ) - and consequently, the exe shows no icon (to be corrected...).
...
Using IDI_APPLICATION is just a convention, any other ID will do.
...
In contrast to the LoadIcon bug in the hello world proggie,


The use of Null as the hInstance parameter in LoadIcon is not a bug. IDI_APPLICATION is a predefined standard icon that must use Null as the hInstance parameter. There are many other standard predefined icons that could be used other than IDI_APPLICATION. Take a look at the documentation for LoadIcon https://docs.microsoft.com/en-us/window ... -loadicona
marcov
Posts: 2650
Joined: Jun 16, 2005 9:45
Location: Eindhoven, NL
Contact:

Re: Another program icon via command line

Postby marcov » Jul 08, 2018 10:39

caseih wrote: The OP is not being very clear about what he's trying to accomplish but it seems he wants to change the embedded icon in a third-party EXE using FB code.


And he probably wants to do it using the program that is edited. That's harder. Probably have to take a copy of the exe, rename the old exe, rename the copy to the "main" name. Now the "alternate" filename is executing. Now modify the exe with the "main" name and exit.

The problem is now that the user must restart the new "main" exe which can then delete the old "alternate" exe.

Usually this (and other self-update scenarios) is done with a little loader app.

Of course a resource editor doesn't have this problem. It isn't running from the binary being edited.

There are perhaps legitimate reasons why you'd want to hack the default icon of a third-party binary. newbieforever has never been very forthcoming with his goals here, and doesn't appear to have done much research before coming to the forum. It's unknown whether his projects are just for personal edification purposes (like most of us on the forum), or something else.

Or have I completely misread what newbieforever was trying to do?


It can be quite benign, like setting the icon to match the configured binary after a setup/configuration stage. Still modifying exes is frowned upon, and the binary doing can expect extra attention (and thus trouble) from antiviruses.

It might be possible (especially without the auto-update problem), but it isn't easy. If it is worth it, is something only OP can tell.
dodicat
Posts: 5355
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Another program icon via command line

Postby dodicat » Jul 08, 2018 13:59

Using jj2007's shellapi idea.
This is the examples hello world tweaked so it creates and loads an icon during compile.

Code: Select all

 

#include once "windows.bi"
#include once "win\shellapi.bi"


dim shared as string  Myicon :Myicon  ="Euro.ico"

declare Sub EURO(x As Integer,y As Integer,s As Single,im As Any Pointer=0) 'creates Myicon


declare function        WinMain     ( byval hInstance as HINSTANCE, _
                                      byval hPrevInstance as HINSTANCE, _
                                      byval szCmdLine as zstring ptr, _
                                      byval iCmdShow as integer ) as integer
                                 
                                 
   end WinMain( GetModuleHandle( null ), null, Command( ), SW_NORMAL )

'':::::
function WndProc ( byval hWnd as HWND, _
                   byval wMsg as UINT, _
                   byval wParam as WPARAM, _
                   byval lParam as LPARAM ) as LRESULT
   
    function = 0
   
    select case( wMsg )
        case WM_CREATE           
            exit function

        case WM_PAINT
          dim rct as RECT
          dim pnt as PAINTSTRUCT
          dim hDC as HDC
         
            hDC = BeginPaint( hWnd, @pnt )
            GetClientRect( hWnd, @rct )
           
            DrawText( hDC, _
                    "Hello, World!", _
                    -1, _
                      @rct, _
                      DT_SINGLELINE or DT_CENTER or DT_VCENTER )
           
            EndPaint( hWnd, @pnt )
           
            exit function           
       
      case WM_KEYDOWN
         if( lobyte( wParam ) = 27 ) then
            PostMessage( hWnd, WM_CLOSE, 0, 0 )
         end if

       case WM_DESTROY
            PostQuitMessage( 0 )
            exit function
    end select
   
    function = DefWindowProc( hWnd, wMsg, wParam, lParam )   
   
end function

'':::::
function WinMain ( byval hInstance as HINSTANCE, _
                   byval hPrevInstance as HINSTANCE, _
                   byval szCmdLine as zstring ptr, _
                   byval iCmdShow as integer ) as integer 
                   '=========== added  ========
                  screen 19,32
dim as any ptr i=imagecreate(128,128)
euro(00,00,2.2,i)
bsave "euro.bmp",i
sleep 50
shell "rename euro.bmp, " + Myicon
imagedestroy (i)
screen 0

                    '===================
     
    dim wMsg as MSG
    dim wcls as WNDCLASS     
    dim hWnd as HWND
    function = 0
     dim as string iconpath=curdir + "\" + Myicon
     dim as integer lpiIcon
    with wcls
       .style         = CS_HREDRAW or CS_VREDRAW
       .lpfnWndProc   = @WndProc
       .cbClsExtra    = 0
       .cbWndExtra    = 0
       .hInstance     = hInstance
       .hIcon         =  ExtractAssociatedIcon(GetModuleHandle(0), iconpath, @lpiIcon) 
       .hCursor       = LoadCursor( NULL, IDC_ARROW )
       .hbrBackground = GetStockObject( WHITE_BRUSH )
       .lpszMenuName  = NULL
       .lpszClassName = @"HelloWin"
    end with
         
    if( RegisterClass( @wcls ) = FALSE ) then
       MessageBox( null, "Failed to register wcls", "Error", MB_ICONERROR )
       exit function
    end if
   
    hWnd = CreateWindowEx( 0, _
                       @"HelloWin", _
                           "The Hello Program", _
                           WS_OVERLAPPEDWINDOW, _
                           CW_USEDEFAULT, _
                           CW_USEDEFAULT, _
                           CW_USEDEFAULT, _
                           CW_USEDEFAULT, _
                           NULL, _
                           NULL, _
                           hInstance, _
                           NULL )
                         

    ShowWindow( hWnd, iCmdShow )
    UpdateWindow( hWnd )
     
    while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )   
        TranslateMessage( @wMsg )
        DispatchMessage( @wMsg )
    wend
    kill  rtrim(Myicon,".ico")+".bmp"'"euro.bmp"
   
    function = wMsg.wParam

end function



'added
Sub EURO(x As Integer,y As Integer,s As Single,im As Any Pointer=0)
    #macro pentagon(starx,stary,size,col)
    Scope
        Var count=0,rad=0.0,_px=0.0,_py=0.0
        For z As Single=0+.28 To 2*pi+.1+.28 Step 2*pi/10
            count=count+1
            If count Mod 2=0 Then rad=size Else rad=.4*size
            _px=starx+rad*Cos(z)
            _py=stary+rad*Sin(z)
            If count=1 Then Pset im,(_px,_py)Else Line im,-(_px,_py),col
        Next z
        Paint im,(starx,stary),col,col
    End Scope
    #endmacro
    Dim As Double pi=4*Atn(1)
    Dim As Integer lx=60*s,ly=1*lx
    Line im,(x,y)-(x+lx,y+ly),Rgb(2,3,192),bf
    Dim As Integer cntx=(x+x+lx)/2,cnty=(y+Y+ly)/2
    For z As Double=0 To 2*pi Step 2*pi/12
        Var px=cntx+.7*(lx/2)*Cos(z)
        Var py=cnty+.7*(lx/2)*Sin(z)
        pentagon(px,py,3*s,Rgb(243,236,24))
    Next z
End Sub


sleep


 
 


I am not sure if newbieforever wants an icon in the window titlebar (as this code), or the whole .exe given an icon which is seen when the .exe is not running .
so I have skipped parameter passing .
newbieforever
Posts: 84
Joined: Jun 21, 2018 11:14

Re: Another program icon via command line

Postby newbieforever » Jul 08, 2018 14:31

UEZ, dodicat & others:

I am overhelmed by your help!

Unfortunately at the moment I am unable to study the codes in detail and to evaluate what can be used for my project (other commitments)...

PS: In case my question was not clear enough: The basic program icon as shown in Windows Explorer should be changed (not the icons displayed directly when 'MyProgram.exe /icon:AnotherIcon.ico' is applied).
caseih
Posts: 1302
Joined: Feb 26, 2007 5:32

Re: Another program icon via command line

Postby caseih » Jul 08, 2018 15:13

Right, so the icon a program displays while running is irrelevant to your purposes, thus playing around with the windows API likely isn't going to solve your problem. Like I said if you do a google search you will find at least one VB program that can change the EXE's icon (which shows up in explorer).
jj2007
Posts: 945
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Another program icon via command line

Postby jj2007 » Jul 08, 2018 16:00

PaulSquires wrote:IDI_APPLICATION is a predefined standard icon that must use Null as the hInstance parameter.
Right, that's what the docs say. Fact is that .hIcon = LoadIcon(0, IDI_APPLICATION) has the same effect as leaving .hIcon zeroed; so you may as well omit that line in hello.bas. If, however, you have something like IDI_APPLICATION ICON "Smiley.ico" in your resource file, you absolutely need GetModuleHandle(0) to see that icon in action.

marcov wrote:he probably wants to do it using the program that is edited. That's harder.
No, it's not hard, it's a one-liner, as explained above. In the unlikely case that with "using the program that is edited" you mean modifying the exe before running it: see below.

newbieforever wrote:PS: In case my question was not clear enough: The basic program icon as shown in Windows Explorer should be changed (not the icons displayed directly when 'MyProgram.exe /icon:AnotherIcon.ico' is applied).
The question was indeed misleading. Explorer uses the icon that is embedded as a resource, but you had explicitly asked to pass a filename in the commandline. There is a logical flaw in that, because passing a commandline implies running the file. Explorer just sees a non-running executable file. So you want to modify the executable, right? Very simple: Rebuild it with a different resource file. Takes half a second...
marcov
Posts: 2650
Joined: Jun 16, 2005 9:45
Location: Eindhoven, NL
Contact:

Re: Another program icon via command line

Postby marcov » Jul 08, 2018 16:26

jj2007 wrote:
marcov wrote:he probably wants to do it using the program that is edited. That's harder.
No, it's not hard, it's a one-liner, as explained above. In the unlikely case that with "using the program that is edited" you mean modifying the exe before running it: see below.


Well. You picked it as the unlikely case. I picked it as the likely case. So the chance is 50-50 :-)

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 2 guests