Changing icons in executables - NT, 2000, XP

Share your advanced PureBasic knowledge/code with the community.
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Changing icons in executables - NT, 2000, XP

Post by traumatic »

Code updated For 5.20+

Code: Select all

;
; Changing icon resources in executables (the NT-API way)
;
;
; NOTE:     Needs NT, 2000 or XP to work
;
;
;
; WARNING:  the following code is known to fail in certain cases
;           be sure to backup your data before using this!
;
;           
;
; (:t)raumatic - february 2005
;


#RT_GROUP_ICON = #RT_ICON + 11


; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp
Structure ICONDIRENTRYCOMMON
  bWidth.b        ; Width, in pixels, of the image
  bHeight.b       ; Height, in pixels, of the image
  bColorCount.b   ; Number of colors in image (0 if >=8bpp)
  bReserved.b     ; Reserved ( must be 0)
  wPlanes.w       ; Color Planes
  wBitCount.w     ; Bits per pixel
  dwBytesInRes.l  ; How many bytes in this resource?
EndStructure

;
Structure ICONDIRENTRY
  common.ICONDIRENTRYCOMMON
  dwImageOffset.l ; Where in the file is this image?
EndStructure

Structure ICONDIR
  idReserved.w              ; Reserved (must be 0)
  idType.w                  ; Resource Type (1 for icons)
  idCount.w                 ; How many images?
  idEntries.ICONDIRENTRY[0] ; An entry for each image (idCount of 'em)
EndStructure


;
Structure GRPICONDIR1ENTRY1
  common.ICONDIRENTRYCOMMON
  nId.w ; the ID
EndStructure

Structure GRPICONDIR1
  idReserved.w                  ; Reserved (must be 0)
  idType.w                      ; Resource type (1 for icons)
  idCount.w                     ; How many images?
  idEntries.GRPICONDIR1ENTRY1[0]  ; The entries for each image
EndStructure



;
; Change Icon-Resource in "exeFilename.s" with "iconFileName.s"
;
Procedure.l ChangeIcon(iconFileName.s, exeFileName.s)
  *icon.ICONDIR = AllocateMemory(SizeOf(ICONDIR))
  
  If ReadFile(0, iconFileName.s)
    ReadData(0, *icon, SizeOf(ICONDIR))
    
    *icon = ReAllocateMemory(*icon, SizeOf(ICONDIR) + (*icon\idCount*2) *SizeOf(ICONDIRENTRY))
    
    For i=0 To *icon\idCount-1
      FileSeek(0, 6+SizeOf(ICONDIRENTRY) * i)  ; SizeOf(ICONDIR) - SizeOf(ICONDIRENTRY) = 6
      ReadData(0, *icon\idEntries[i], SizeOf(ICONDIRENTRY) * (i+1))
    Next
    
    ;
    hInst.l = BeginUpdateResource_(exeFileName, #False)
    If hInst = 0
      retVal.l = #False
    Else
      
      ; CHANGE #RT_GROUP_ICON
      *iconGroup.GRPICONDIR1 = AllocateMemory(SizeOf(GRPICONDIR1) + 6 + SizeOf(GRPICONDIR1ENTRY1) * *icon\idCount)
      For i=0 To *icon\idCount-1
        CopyMemory(*icon\idEntries[i]\common, *iconGroup\idEntries[i]\common, SizeOf(ICONDIRENTRYCOMMON))
        *iconGroup\idEntries[i]\nId = (i+1)
      Next
      
      *iconGroup\idReserved = 0
      *iconGroup\idType     = 1
      *iconGroup\idCount    = *icon\idCount
      
      ;
      ; TODO: Error with bColorCount
      ;       Written value is always wrong!? (e.g. 1 instead of 16)
      ;
      
      retVal = UpdateResource_(hInst, #RT_GROUP_ICON, 1, #LANG_NEUTRAL, *iconGroup, 6+SizeOf(GRPICONDIR1ENTRY1)* *iconGroup\idCount)
      FreeMemory(*iconGroup) : *iconGroup = #Null
      
      
      ; CHANGE #RT_ICON
      For i = 0 To *icon\idCount-1
        ; get the desired icon from .ico file
        *resData = AllocateMemory(*icon\idEntries[i]\common\dwBytesInRes)
        FileSeek(0, *icon\idEntries[i]\dwImageOffset)
        ReadData(0, *resData, *icon\idEntries[i]\common\dwBytesInRes)
        
        retVal = UpdateResource_(hInst, #RT_ICON, (i+1), #LANG_NEUTRAL, *resData, *icon\idEntries[i]\common\dwBytesInRes)
      Next
      
      retVal = EndUpdateResource_(hInst, #False)
      
      FreeMemory(*resData) : *resData = #Null
    EndIf
    
    FreeMemory(*icon) : *icon = #Null
    CloseFile(0)
    
  Else
    retVal = #False
  EndIf
  
  ProcedureReturn retVal
EndProcedure
Good programmers don't comment their code. It was hard to write, should be hard to read.
acidburn
User
User
Posts: 23
Joined: Mon Aug 07, 2006 1:37 pm

Post by acidburn »

great job
..::Origin::..
Enthusiast
Enthusiast
Posts: 125
Joined: Sat Jun 17, 2006 3:15 pm

Post by ..::Origin::.. »

Great! I can't really find a use for this, but what about an Icon extractor? That i could find many uses for :)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

..::Origin::.. wrote:Great! I can't really find a use for this, but what about an Icon extractor? That i could find many uses for :)
Here's one:

Code: Select all

; Idea from Rikuk 
; File specifies the file where icon is extracted 
; icon = 0 to ? --> Return handle of image 
; icon = -1 --> Return the count of icon 

Procedure IconExtract(File.s,Icon.l) 
  ProcedureReturn ExtractIcon_(0,File,Icon) 
EndProcedure 

;/ Test 
#file="shell32.dll" 
Count=IconExtract(#file,-1) 
OpenWindow(0,0,0,130,70,Str(Count)+" Icons",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) 
CreateGadgetList(WindowID(0)) 
ButtonImageGadget(0,10,10,48,48,IconExtract(#file,pointer)) 
TextGadget(1,80,30,40,20,"n° 1") 

Repeat 
  event=WaitWindowEvent() 
  
  If event= #PB_Event_Gadget And EventGadget()=0 And EventType()=#PB_EventType_LeftClick 
    pointer+1 
    If pointer=Count : pointer=0 : EndIf 
    SetGadgetState(0,IconExtract(#file,pointer)) 
    SetGadgetText(1,"n° "+Str(pointer+1)) 
  EndIf 
Until event=#PB_Event_CloseWindow
I may look like a mule, but I'm not a complete ass.
User avatar
aston
User
User
Posts: 64
Joined: Wed Nov 18, 2009 11:18 pm

Re: Changing icons in executables - NT, 2000, XP

Post by aston »

I know that this topic is really old but i found it just now
when i need such a small app or better to say utility which change executable icon
but only in explorer or folder view ...

is there a way to improve this to update application icon (window icon ) ?
any example maybe ?
thanks

here is my code i compiled with old v4.5

Code: Select all

;Changing icon resources in executables (the NT-API way)
;
; NOTE:     Needs NT, 2000 or XP to work
;
; WARNING:  the following code is known to fail in certain cases
;           be sure to backup your data before using this!
;
; (:t)raumatic - february 2005
;

#RT_GROUP_ICON = #RT_ICON + 11

; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp
Structure ICONDIRENTRYCOMMON
  bWidth.b        ; Width, in pixels, of the image
  bHeight.b       ; Height, in pixels, of the image
  bColorCount.b   ; Number of colors in image (0 if >=8bpp)
  bReserved.b     ; Reserved ( must be 0)
  wPlanes.w       ; Color Planes
  wBitCount.w     ; Bits per pixel
  dwBytesInRes.l  ; How many bytes in this resource?
EndStructure

;
Structure ICONDIRENTRY
  common.ICONDIRENTRYCOMMON
  dwImageOffset.l ; Where in the file is this image?
EndStructure

Structure ICONDIR
  idReserved.w              ; Reserved (must be 0)
  idType.w                  ; Resource Type (1 for icons)
  idCount.w                 ; How many images?
  idEntries.ICONDIRENTRY[0] ; An entry for each image (idCount of 'em)
EndStructure


;
Structure GRPICONDIR1ENTRY1
  common.ICONDIRENTRYCOMMON
  nId.w ; the ID
EndStructure

Structure GRPICONDIR1
  idReserved.w                  ; Reserved (must be 0)
  idType.w                      ; Resource type (1 for icons)
  idCount.w                     ; How many images?
  idEntries.GRPICONDIR1ENTRY1[0]  ; The entries for each image
EndStructure



;
; Change Icon-Resource in "exeFilename.s" with "iconFileName.s"
;ChangeIcon("window.exe","myicon.ico")
;
Procedure.l ChangeIcon(iconFileName.s, exeFileName.s)
  *icon.ICONDIR = AllocateMemory(SizeOf(ICONDIR))
  
  If ReadFile(0, iconFileName.s)
    ReadData(0, *icon, SizeOf(ICONDIR))
    
    *icon = ReAllocateMemory(*icon, SizeOf(ICONDIR) + (*icon\idCount*2) *SizeOf(ICONDIRENTRY))
    
    For i=0 To *icon\idCount-1
      FileSeek(0, 6+SizeOf(ICONDIRENTRY) * i)  ; SizeOf(ICONDIR) - SizeOf(ICONDIRENTRY) = 6
      ReadData(0, *icon\idEntries[i], SizeOf(ICONDIRENTRY) * (i+1))
    Next
    
    ;
    hInst.l = BeginUpdateResource_(exeFileName, #False)
    If hInst = 0
      retVal.l = #False
    Else
      
      ; CHANGE #RT_GROUP_ICON
      *iconGroup.GRPICONDIR1 = AllocateMemory(SizeOf(GRPICONDIR1) + 6 + SizeOf(GRPICONDIR1ENTRY1) * *icon\idCount)
      For i=0 To *icon\idCount-1
        CopyMemory(*icon\idEntries[i]\common, *iconGroup\idEntries[i]\common, SizeOf(ICONDIRENTRYCOMMON))
        *iconGroup\idEntries[i]\nId = (i+1)
      Next
      
      *iconGroup\idReserved = 0
      *iconGroup\idType     = 1
      *iconGroup\idCount    = *icon\idCount
      
      ;
      ; TODO: Error with bColorCount
      ;       Written value is always wrong!? (e.g. 1 instead of 16)
      ;
      
      retVal = UpdateResource_(hInst, #RT_GROUP_ICON, 1, #LANG_NEUTRAL, *iconGroup, 6+SizeOf(GRPICONDIR1ENTRY1)* *iconGroup\idCount)
      FreeMemory(*iconGroup) : *iconGroup = #Null
      
      
      ; CHANGE #RT_ICON
      For i = 0 To *icon\idCount-1
        ; get the desired icon from .ico file
        *resData = AllocateMemory(*icon\idEntries[i]\common\dwBytesInRes)
        FileSeek(0, *icon\idEntries[i]\dwImageOffset)
        ReadData(0, *resData, *icon\idEntries[i]\common\dwBytesInRes)
        
        retVal = UpdateResource_(hInst, #RT_ICON, (i+1), #LANG_NEUTRAL, *resData, *icon\idEntries[i]\common\dwBytesInRes)
      Next
      
      retVal = EndUpdateResource_(hInst, #False)
      
      FreeMemory(*resData) : *resData = #Null
    EndIf
    
    FreeMemory(*icon) : *icon = #Null
    CloseFile(0)
    
  Else
    retVal = #False
  EndIf
  
  ProcedureReturn retVal
EndProcedure

;open window and add two buttons and two edit controls (gadgets pb way )
If OpenWindow(0, 0, 0, 500, 300, "Change_Exe_Icon", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   ; create two buttons
    ButtonGadget(0, 10, 10, 100 , 23, "Select Icon File")
    ButtonGadget(1, 10, 100, 100, 23, "Select Exe File")
    ;edit controls
    StringGadget(3, 10, 50, 400, 23,"")
    StringGadget(4, 10, 150, 400, 23,"")
    ; change icon button ...execute function
     ButtonGadget(5, 10, 200, 100, 48, "Change Exe Icon")
 
    
   ;events.... 
    Repeat 
      
    EventID = WaitWindowEvent()
    
    If EventID = #PB_Event_Gadget
      
      Select EventGadget() 
          
        Case 0
          iconFile$ = OpenFileRequester("Open icon file...", "", "Icon file(*.ico)|*.ico;*.bat", 0)
            If iconFile$ + iconFile$
              ;MessageRequester("Information", "Selected File: " + iconFile$, 0);         
            ; set control text
            SetGadgetText(3, iconFile$)
          EndIf
                    
        Case 1
          exeFile$ = OpenFileRequester("Open exe file...", "", "Exe file(*.exe)|*.exe;*.bat", 0)
            If exeFile$ + exeFile$
              ; MessageRequester("Information", "Selected File: " + exeFile$, 0);
               SetGadgetText(4, exeFile$)            
             EndIf
             
        Case 5
           ChangeIcon(iconFile$, exeFile$)  
      
      
      EndSelect
      
    EndIf 
    
    ;Until WaitWindowEvent() = #PB_Event_CloseWindow
    Until EventID = #PB_Event_CloseWindow
  EndIf


 
Post Reply