Functions for Resource-Only DLL

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

DllPackIcons()

20 Sep 2017, 15:13

DllPackIcons( Folder, DLL, nICON, nGROUPICON )

Code: Select all

DllPackIcons( Folder, DLL, nICON:=1, nGROUPICON:=1 ) {  ; By SKAN | 21-Sep-2017 | goo.gl/DjDxzW
  Local RT_ICON := 3, RT_GROUPICON := 14, hUPD := 0
  Local ICONDATA, nBytes, nOffset, ICONDIR, ICONDIRENTRY, nImages, pICONDIRENTRY 
  Local File, fICONDIRENTRY, fList := "", IsFolder := 0 

  nICON := ( nICON<1 ? 1 : nICON ),     nGROUPICON := ( nGROUPICON<1 ? 1 : nGROUPICON )

  If ( IsFolder := DllCall( "shlwapi\PathIsDirectory", "Str",Folder ) )
     Loop, Files, %Folder%\*.*
       fList .= A_LoopFileLongPath "`n"
  fList := Trim( IsFolder ? fList : Folder, "`n`r" )        
           
  Loop, Parse, fList, `n, `r
  {
      If ( DllCall( "Shell32\ExtractIcon", "Ptr",0, "Str",A_LoopField, "Int",-1 ) <> 1 )
        Continue

      File := FileOpen(A_LoopField,"r-wd")
      If ( IsObject(File)=0 Or File.ReadUINT()<>0x00010000 )
      { 
          File.Close()
          Continue
      }     

      hUPD := ( hUPD ? hUPD : DllCall( "BeginUpdateResource", "Str",DLL, "Int",0, "Ptr" ) )
      nImages := File.ReadUSHORT()
      VarSetCapacity(ICONDIRENTRY,14*nImages+6,0)
      File.Seek(0,0)
      File.RawRead(ICONDIRENTRY,6)
      pICONDIRENTRY := &ICONDIRENTRY+6
      fICONDIRENTRY := 6
      Loop % nImages
      {
          File.Seek(fICONDIRENTRY,0)
          File.RawRead(pICONDIRENTRY+0,16)
          nBytes  := NumGet(pICONDIRENTRY+ 8,"UInt")
          nOffset := NumGet(pICONDIRENTRY+12,"UInt")
          NumPut( nICON,pICONDIRENTRY+12,"UShort")
          File.Seek(nOffset,0) 
          File.RawRead( ICONDATA, nBytes )

          DllCall( "UpdateResource", "Ptr",hUPD, "Ptr",RT_ICON, "Ptr",nICON
                                   , "Int",0, "Ptr",&ICONDATA, "UInt",nBytes )
          nICON += 1
          pICONDIRENTRY += 14 
          fICONDIRENTRY += 16
      } 
      DllCall( "UpdateResource", "Ptr",hUPD, "Ptr",RT_GROUPICON, "Ptr",nGROUPICON
                               , "Int",0, "Ptr",&ICONDIRENTRY, "UInt",14*nImages+6 )
      nGROUPICON += 1
      File.Close()
  }
  hUPD := ( hUPD ? DllCall( "EndUpdateResource", "Ptr",hUPD, "Int",0 ) >> 64 : 0 )
Return 1
}


Example 1:
Icons will be added in the order populated by File system.
It NTFS, The .ICO files will be in alphabetical order and in FAT32 the list will be in no particular order.

Code: Select all

DLL := DllCreateEmpty( A_ScriptDir "\Icons.dll" )
DllPackIcons( "D:\MyIcons\", DLL )
Example 2:
Icons will be added exactly as it appears in the "files" list.

Code: Select all

DLL := DllCreateEmpty( A_ScriptDir "\Icons.dll" )
Files := "
(
D:\MyIcons\Icon3.ico
D:\MyIcons\Icon1.ico
D:\MyIcons\Icon2.ico
)"
DllPackIcons( Files, DLL )
My Scripts and Functions: V1  V2
User avatar
hoppfrosch
Posts: 443
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: Functions for Resource-Only DLL

21 Sep 2017, 04:39

Thanks SKAN - my tests work without a flaw yet...! :dance:

What would be nice (but I don't know whether it's possible at all): name the icons within the DLL according their filenames (without extension of course) - instead of using an anonymous number ....
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Functions for Resource-Only DLL

21 Sep 2017, 05:55

It's possible for icon groups, but afaik you cannot extract an icon by name using the built-in AHK commands/functions.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Functions for Resource-Only DLL

21 Sep 2017, 12:10

hoppfrosch wrote:Thanks SKAN - my tests work without a flaw yet...! :dance:
Glad to know.
I forgot to mention:
DllPackIcons() doesn't trust file extensions. Each and every file is opened and confirmed to have an ICONDIR in header.
This is because .BMP files can be renamed to .ICO and Windows will accept/load it as icon.
So, If you have a .ICO that is not being added, make sure it isn't a BMP file.
What would be nice (but I don't know whether it's possible at all): name the icons within the DLL according their filenames (without extension of course)
I had thought of it. As just me said, the names aren't very useful as AutoHotkey loads icon by its position (1 based index) rather than its ID.
Also implementing it would be hard. For example, if icon filename is either "HOPP.ico" or "123.ico", I know the first one should be saved as string and the latter as a number. What if you order/name your icons like "0001.ico", "0002.ico... "1234.ico".
Then I will have to accept a filelist as a CSV with two parameters.
hoppfrosch wrote:instead of using an anonymous number ....
The numbers matches actual index AutoHotkey uses. If you look at the code, you may see that the functions doesn't allow using 0 as the starting number, specifically for this reason (and also: 0 should be stored as a string)

:)
My Scripts and Functions: V1  V2
User avatar
hoppfrosch
Posts: 443
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: Functions for Resource-Only DLL

25 Sep 2017, 00:01

Naming is not really a problem - I just had my icons clearly named and was "disappointed" at the first look, after seeing my names got lost within the dll. I'm fine with this.

Thanks SKAN for your great work. :clap:
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: Functions for Resource-Only DLL

25 Sep 2017, 17:47

the names aren't very useful as AutoHotkey loads icon by its position (1 based index) rather than its ID.
if you wanted to use named icon group resources you can access them by the native winapi calls, LoadIcon or LoadImage

Probably more trouble than its worth in most cases, but if you had lots of icons to deal with it might be beneficial in some cases
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Chunjee, gwarble, hiahkforum and 60 guests