Change exe icon

Started by Zlatko Vid, July 03, 2022, 06:30:19 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Zlatko Vid

I was looking into simple code around net to find is there a way
to change icon of compiled executable file  .exe
and found one on PureBasic forum ...
this program use few win api functions and some specific from pureBasic
Now i am wondering how translate this to o2 code ...

ps ..should be great to have simple mini program which can open FileDialog and
that user can itself add his own icon (.ico) to already created exe.
I tested pb program and work well on my win7_64bit

here is PureBasic code :

;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

ChangeIcon("myIcon.ico","window.exe")

Charles Pegge

Thanks Aurel, I'm working on it! The procedure is not as complex as first appears, especially when loading the whole ico file into one string.

Zlatko Vid

Charles
GUI part is not problematic but code inself kind a is
This program olnly change exe icon in explorer (folder) view not  window icon or
application icon...

i found few things on stackover :

HGLOBAL hResLoad;   // handle to loaded resource
HMODULE hExe;       // handle to existing .EXE file
HRSRC hRes;         // handle/ptr. to res. info. in hExe
HANDLE hUpdateRes;  // update resource handle
LPVOID lpResLock;   // pointer to resource data
BOOL result;

hExe = LoadLibrary(TEXT("app.exe"));
if (hExe == NULL)
{
  return;
}

// Locate the icon resource in the .EXE file.
hRes = FindResource(hExe, MAKEINTRESOURCE(IDI_TB_SAVE), RT_GROUP_ICON);
if (hRes == NULL)
{
  return;
}

// Load the resource into global memory.
hResLoad = LoadResource(hExe, hRes);
if (hResLoad == NULL)
{
  return;
}

// Lock the resourcex into global memory.
lpResLock = LockResource(hResLoad);
if (lpResLock == NULL)
{
  return;
}

// Open the file to which you want to add the icon resource.
hUpdateRes = BeginUpdateResource(TEXT("app_updated.exe"), FALSE);
if (hUpdateRes == NULL)
{
  return;
}

result = UpdateResource(hUpdateRes,    // update resource handle
  RT_GROUP_ICON,                         // change icon resource
  MAKEINTRESOURCE(IDR_MAINFRAME),         // resource id
  MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),  // english
  lpResLock,                         // ptr to resource info
  SizeofResource(hExe, hRes));       // size of resource info

if (result == FALSE)
{
  return;
}

// Write changes to app_updated.exe and then close it.
if (!EndUpdateResource(hUpdateRes, FALSE))
{
  return;
}

// Clean up.
if (!FreeLibrary(hExe))
{
  return;
}


but :
-------------------------------------------------
MAKEINTRESOURCE
The MAKEINTRESOURCE macro converts an integer value to a resource type compatible with Win32 resource-management functions. This macro is used in place of a string containing the name of the resource.
LPTSTR MAKEINTRESOURCE(
WORD wInteger
// integer to convert
);

Parameters
wInteger
Specifies the integer value to be converted.
Return Values
The return value is the specified value in the low-order word and zero in the high-order word.
Remarks
The return value should be passed only to the Win32 resource-management functions, as the lpType parameter.
The MAKEINTRESOURCE macro is defined as follows:
#define MAKEINTRESOURCE(i) (LPTSTR) ((DWORD) ((WORD) (i)))

so how translate this macro to o2?
such a simple tool should be great to have to change program icon
without resource editor or something complex
do you agree ?

Charles Pegge

#3
Hi Aurel,

MAKEINTRESOURCE turns an integer into a string representation of the value

For instance,  integer 31 becomes "#31"

as a macro in o2:

def  MAKEINTRESOURCE "#%1"
print MAKEINTRESOURCE(31)

to convert to a unicode string, store the result in a wstring

wstring s=MAKEINTRESOURCE(31)



PS I don't think the # is necessary

Zlatko Vid

Hi Charles

It looks strange to me ..i never work with resources before
if i mix up something about icons i will post it .

Charles Pegge

I see that UpdateResourceW accepts numbers directly for params ResType and ResName. It is smart enough to distinguish between string pointers and direct equate values.

Charles Pegge

Here is my loose translation to o2, including some diagnostics:


/*
;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
;
;

translated to OxygenBasic  Charles E V Pegge 06/07/2022

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp
*/

uses corewin

% RT_ICON 3
% RT_GROUP_ICON  14
% LANG_NEUTRAL 0x000 '0xc00


type ICONDIRENTRYCOMMON
  byte  bWidth        ' Width, in pixels, of the image
  byte  bHeight       ' Height, in pixels, of the image
  byte  bColorCount   ' Number of colors in image (0 if >=8bpp)
  byte  bReserved     ' Reserved ( must be 0)
  word  wPlanes       ' Color Planes
  word  wBitCount     ' Bits per pixel
  dword dwBytesInRes  ' How many bytes in this resource?
end type
'12 bytes


type ICONDIRENTRY_A
  has ICONDIRENTRYCOMMON
  dword               dwImageOffset ' Where in the file is this image?
end type
'16 bytes


type ICONDIRENTRY_B
  has ICONDIRENTRYCOMMON
  'word                nId ' the ID
  'word                padding
  dword                nId 'dword to ensure upper word is zero
end type
'16 bytes


type ICONDIR
  word idReserved           ' Reserved (must be 0)
  word idType               ' Resource Type (1 for icons)
  word idCount              ' How many images?
end type
'6 bytes + ENTRYS FOLLOW IMMEDIATELY


function ViewIconData(string buf) as string
===========================================
indexbase 0
int i 'iterator
string pr 'return info
ICONDIR *id
ICONDIRENTRY_A *ie

@id = strptr(buf)
@ie = @id+6
pr="
Icon group header 
Reserved: " id.idReserved "
Type:     " id.idType "
Count:    " id.idCount "
Entry 1:
pixel width:      " ie.bWidth "
pixel height:     " ie.bHeight "
color count:      " ie.bColorCount "
reserved :        " ie.bReserved "
planes:           " ie.wPlanes "
bits per pixel:   " ie.wBitCount "
byte count:       " ie.dwBytesInRes "
file loc/ordinal: " ie.dwImageOffset "
"
return pr
end function


function ViewIconFileData(string iconFileName) as string
========================================================
string buf = getfile(iconFileName)
string pr 'return info
if not buf
  pr="Icon file not found: " iconFileName
else
  pr=ViewIconData(buf)
endif
return pr
end function


'print ViewIconFileData "oxicon.ico"
'print ViewIconFileData "oxideicon.ico"


function ChangeIcon(string iconFileName, exeFileName) as int
============================================================
indexbase 0
int lang =  0x0 '0x409 LANG_US, 0x0 LANG_NEUTRAL
int i 'iterator

string buf = getfile(iconFileName)
if len(buf)=0
  return 0
endif
'
sys hRes = BeginUpdateResource(exeFileName, 0)
If hRes = 0
  return 0
endif
'
ICONDIR *icon
@icon = strptr(buf)
int count = icon.idCount
'
'CHANGE RT_GROUP_ICON (14)
'-------------------------
'
'copy of icon directory to be modified for group
string gbuf
gbuf=buf
ICONDIR *ig
@ig = strptr(gbuf)
ig.idReserved = 0
ig.idType     = 1
ig.idCount    = count
'
ICONDIRENTRY_B *ie
@ie=strptr(gbuf)+6
for i=0 to count-1
  ie[i].nId = i+1 'replacing ImageOffset
next
'   
int lg = 6 + SizeOf(ie) * count
function = UpdateResource( hRes, 14, 1, lang , ig, lg )
gbuf=""
'
' CHANGE EACH RT_ICON (3)
'------------------------
'
sys pbuf=strptr(buf)
sys pdat ' pointer to icon data
int ldat ' length of icon data
ICONDIRENTRY_A *ie
@ie=pbuf+6
for i = 0 to count-1
  ' get each icon from .ico file
  ldat = ie[i].dwBytesInRes
  pdat = pbuf + ie[i].dwImageOffset
  function = UpdateResource( hRes , 3, i+1 , lang , pdat, ldat )
next
'
return EndUpdateResource(hRes, 0)
 
end function

'ChangeIcon("OxIcon.ico","co2.exe")


Zlatko Vid

Thanks Charles
I will try ..hope that work for me