Pre-built ImageLists - credits to SKAN

Post your working scripts, libraries and tools for AHK v1.1 and older
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Pre-built ImageLists - credits to SKAN

26 Dec 2017, 05:56

While ckecking some of my own ImageList functions I came across the API functions ImageList_Write() and ImageList_Read() once again. This time I felt to be ready to write wrappers for this functions. As already often before, I immediately started to gather the needed information. Not before I had found all I needed I searched the forums. And, as so often in the past, I found that SKAN already did it -> ImageList :: Save/Load/LoadRes/SaveAsBMP + Viewer .

IMO, the functions provide a useful additional option to share own icons or images by only one file. That's why I decided to post revised versions of SKAN's functions in the new forum.

Code: Select all

#NoEnv
SetBatchLines, -1
ImlFile := "Test.iml"
; --------------------------------------------------------------------------------------------------------------------------------
HIL1 := IL_Create(10, 0, 1)
Loop, 40
   IL_Add(HIL1, "Shell32.dll", A_Index)
Gui, Add, Text, xm w480, Loaded from Shell32.dll:
Gui, Add, ListView, xm y+2 w480 h510 Icon, Icon
LV_SetImageList(HIL1, 0)
Loop, 40
   LV_Add("Icon" . A_Index )
; --------------------------------------------------------------------------------------------------------------------------------
IL_Save(HIL1, ImlFile)
HIL2 := IL_Load(ImlFile)
Gui, Add, Text, ym w480, Loaded from saved ImageList:
Gui, Add, ListView, xp y+2 w480 h510 Icon, Icon
LV_SetImageList(HIL2, 0)
Loop, 40
   LV_Add("Icon" . A_Index )
; --------------------------------------------------------------------------------------------------------------------------------
Gui, Add, Text, xm, Icon 1 from loaded ImageList:
Gui, Add, Pic, xm y+2 Border, % "HICON:" . IL_EX_GetHICON(HIL2, 1)
Gui, Show, , ImageList Test
Return
; ================================================================================================================================
GuiClose:
FileDelete, %ImlFile%
ExitApp
; ================================================================================================================================
IL_Save(HIL, File) {
   ; Originally released by SKAN -> www.autohotkey.com/forum/viewtopic.php?t=72282
   Size := 0
   If (FileObj := FileOpen(File, "w")) {
      DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", 0, "Int", 1, "PtrP", IStream, "UInt")
      DllCall("ImageList_Write", "Ptr", HIL, "Ptr", IStream, "UInt")
      DllCall("Ole32.dll\GetHGlobalFromStream", "Ptr", IStream, "PtrP", HGlobal, "UInt")
      Data := DllCall("GlobalLock", "Ptr", HGlobal )
      Size := DllCall("GlobalSize", "Ptr", HGlobal )
      Size := FileObj.RawWrite(Data + 0, Size)
      FileObj.Close()
      DllCall("GlobalUnlock", "Ptr", Data)
      ObjRelease(IStream)
      DllCall("GlobalFree", "Ptr", HGlobal)
   }
   Return Size
}
; ================================================================================================================================
IL_Load(File) {
   ; Originally released by SKAN -> www.autohotkey.com/forum/viewtopic.php?t=72282
   HIL := 0
   If (FileObj := FileOpen(File, "r")) {
      Size := FileObj.Length
      HGlobal := DllCall("GlobalAlloc", "UInt", 2, "UInt", Size, "UPtr")
      Data := DllCall("GlobalLock",  "Ptr", HGlobal, "UPtr")
      FileObj.RawRead(Data + 0, Size)
      FileObj.Close()
      DllCall("GlobalUnlock", "Ptr", Data)
      DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", HGlobal, "Int", 1, "PtrP", IStream, "UInt")
      HIL := DllCall("ImageList_Read", "Ptr", IStream, "UPtr")
      ObjRelease(IStream)
      DllCall("GlobalFree", "Ptr", HGlobal)
   }
   Return HIL
}
; ======================================================================================================================
; Part of the IL_EX library -> autohotkey.com/boards/viewtopic.php?f=6&t=1273
; ======================================================================================================================
; IL_EX_GetHICON(ILID, Index[, Styles := 0x00])
; Function:       Creates an icon from an image in an image list.
; Parameters:     Styles   -  A combination of drawing styles (see IL_EX_Draw()).
;                             Default: 0x20 (ILD_IMAGE)
; Return values:  Returns the handle to the icon if successful, or NULL otherwise.
; MSDN:           http://msdn.microsoft.com/en-us/library/bb761548(VS.85).aspx
; ======================================================================================================================
IL_EX_GetHICON(ILID, Index, Styles := 0x20) {
   Return DllCall("ComCtl32.dll\ImageList_GetIcon", "Ptr", ILID, "Int", Index - 1, "UInt", Styles, "UPtr")
}
Update on 2017-12-29:
  • Changed IL_Load() to work on Win XP.
    The previously used SHCreateMemStream() function is not exported by name on XP, thanks Drugwash.
Edit on 2017-12-30:
:arrow: IL_Load_VBMP() (requested by Drugwash)
This function can be used to load 'vertically-stacked' bitmaps as used by some Windows themes from BMP files on Win XP+. It has been tested with some few files only, so it might not work properly in every case.
Last edited by just me on 30 Dec 2017, 03:53, edited 2 times in total.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

26 Dec 2017, 09:56

In SKAN's post #9 of the original topic he says the image list is practically a vertically-stacked collection of bitmaps and the whole image list is a bitmap - IL Header apart. How about a convertor function that would take a bitmap and return an image list, and the other way around, provided it's fed with the necessary details? The original IML_Save() can save an image list as a bitmap but I don't think IML_Load() can load a bitmap as an image list, and that's precisely what I'd need.
Windows theme bitmaps come vertically stacked and such function may be of use for a viewer/editor (I have something like that for 98SE RP themes).
Part of my AHK work can be found here.
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

26 Dec 2017, 11:09

Isn't it the task of ImageList_LoadImage()?
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

26 Dec 2017, 11:59

If I'm not mistaken, that API will only load a horizontally stacked bitmap. Height cannot be calculated for a vertically-stacked image, it has to be specified by the user or the IL Header.
MSDN wrote:cx
Type: int
The width of each image. The height of each image and the initial number of images are inferred by the dimensions of the specified resource.
I've struggled with those API at some point but couldn't find the vertical stack loading. I even have my own ImageList library used in some of my scripts.
Part of my AHK work can be found here.
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

26 Dec 2017, 17:20

You're right. Do you have any example of such a vertically stacked bitmap taken from a theme file?
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 08:14

Here you are, a vertical slider button from my current Windows 7 ROSE custom theme, saved by ResHacker:
00389.7z
(1.69 KiB) Downloaded 82 times
Part of my AHK work can be found here.
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 10:56

I see two ways, both requiring that you know the height of each image:
  1. Convert the vertically stacked bitmap into a horizontally stacked and use ImageList_LoadImage().
  2. Add an IL header to the bitmap file contents after reading and use ImageList_Read().
I couldn't find any useful info about the IL header. Maybe someone else will have more luck. The header in the test file created by the script in the OP is

Code: Select all

494C200628002C00040020002000FFFFFF002100FFFFFFFFFFFFFFFF
I tried to analyse it but almost all of my 'result' is pure guessing as yet:

Code: Select all

; IL Header                                                    Size
; Char         49          I                                   1
; Char         4C          L                                   1
; Char ?       20          Space       ?                       1
; Char ?       06                      version?                1
; Short ?      0028        40          number of images?       2
; Short ?      002C        44          ?                       2
; Short ?      0004        4           ?                       2
; Short ?      0020        32          width?                  2
; Short ?      0020        32          height?                 2
; Integer ?    00FFFFFF                color white?            4
; Short ?      0021        33          ?                       2
; Integer ?    FFFFFFFF                CLR_NONE?               4
; Integer ?    FFFFFFFF                CLR_NONE?               4
;                                                             28
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 11:12

just me wrote:I couldn't find any useful info about the IL header.
Not that I know anything about this myself, but there's this from ReactOS.

EDIT:

(Sorry, I'll just edit this post - I feel this would just clutter up your thread as a new post :-))

:wave:

Hey, just me. No problem. Good luck (though I'm sure you won't need it)!
Drugwash wrote:Glad to see you back, qwerty12! :wave:
Hey, Drugwash. It's good to see you around, too!
Last edited by qwerty12 on 27 Dec 2017, 12:35, edited 1 time in total.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 11:17

Second solution looks a tad easier, provided we find the right meaning to all the fields in an ImageList header.
I always ask myself: how does the system do it, while so many developers out there struggle with mockups?
Since Windows themes (at least in XP) use vertically stacked images there must be an easier way to load them either individually or as an ImageList.
Many other system images come as one large bitmap that's being processed (how?) to retrieve a certain area/subimage by a multiple of width and height.
Part of my AHK work can be found here.
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 12:13

Hi querty12,

thank you very much. With this information, I'll try write a loader function for this kind of 'image lists'.

@Drugwash: I'm pretty sure that MS has some secret functions to do this job.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 12:20

Oh, they do have a lot of secrets! And they need to be uncovered. ;)

Glad to see you back, qwerty12! :wave:
Part of my AHK work can be found here.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 14:16

[maybe of interest]
Wine API: ImageList_Read
https://source.winehq.org/WineAPI/ImageList_Read.html
[blank]
Wine API: ImageList_Write
https://source.winehq.org/WineAPI/ImageList_Write.html
[a few things here: IMAGELIST / ILC_]
CommCtrl.h
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

27 Dec 2017, 16:29

Thanks!
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

28 Dec 2017, 04:11

Hi Drugwash,

if you run my script (after commenting out the FileDelete) on XP / Win7, do you get an IL header different from

Code: Select all

494C200628002C00040020002000FFFFFF002100FFFFFFFFFFFFFFFF
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

28 Dec 2017, 06:05

There's either a typo in your code string or a difference on my machine:
20171228125023.png
20171228125023.png (23.29 KiB) Viewed 4452 times
However, the saved IML is not being loaded here on XP. Only the shell32 list is visible, the right-side list is empty because SHCreateMemStream() is not present by name in shlwapi.dll so IL_Load() can't work. According to Geoff Chappell it's been exported as ordinal 12 since shell v4.71 and it's been exported by name only since Vista.
Part of my AHK work can be found here.
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Pre-built ImageLists - credits to SKAN

28 Dec 2017, 10:42

Hi Drugwash,

based on the ReactOS source (thanks again, querty12) and after many 'try & error' I finally managed to load your sample BMP.

Code: Select all

/* Header used by ImageList_Read() and ImageList_Write() */
#include "pshpack2.h"
typedef struct _ILHEAD
{
    USHORT	usMagic;
    USHORT	usVersion;
    WORD	cCurImage;
    WORD	cMaxImage;
    WORD	cGrow;
    WORD	cx;
    WORD	cy;
    COLORREF	bkcolor;
    WORD	flags;
    SHORT	ovls[4];
} ILHEAD;
#include "poppack.h"
The following seems to be important for your file:
  • usVersion must be set to 0x0600. 0x0620 does not work for me, but 0x0600 also loads files with stripped IL header created by ImageList_Write() on my system.
  • cMaxImage must be equal to cCurImage for your file.
  • cy * cMaxImage must match the height of the bitmap in every case.
  • flags must not include ILC_MASK (0x00000001) for your file.

Code: Select all

#NoEnv
SetBatchLines, -1
; --------------------------------------------------------------------------------------------------------------------------------
ImlFile := "00389.bmp"
ImageCount := 5
HIL2 := IL_Load_VBMP(ImlFile, ImageCount)
Gui, Add, Text, ym w480, Loaded from saved ImageList:
Gui, Add, ListView, xp y+2 w480 h510 BackgroundSilver Icon, Icon
LV_SetImageList(HIL2, 0)
Loop, %ImageCount%
   LV_Add("Icon" . A_Index )
Gui, Show, , ImageList Test
Return
; ================================================================================================================================
GuiClose:
ExitApp
; ================================================================================================================================
IL_Load_VBMP(File, ImageCount, BkColor := 0xFFFFFF) {
   HIL := 0
   If (FileObj := FileOpen(File, "r")) {
      Size := FileObj.Length + 28 ; size Of ILHEAD = 28
      HGlobal := DllCall("GlobalAlloc", "UInt", 2, "UInt", Size, "UPtr")
      Data := DllCall("GlobalLock",  "Ptr", HGlobal, "UPtr")
      FileObj.RawRead(Data + 28, FileObj.Length)
      FileObj.Close()
      Width := NumGet(Data + 28, 18, "Int")
      Height := NumGet(Data + 28, 22, "Int")
      BitCount := NumGet(Data + 28, 28, "Short")
      ; ---------------------------------------------------------------
      StrPut("IL", Data, 2, "CP0")                          ; usMagic
      NumPut(0x0600, Data + 2, "Short")                     ; usVersion
      NumPut(ImageCount, Data + 4, "Short")                 ; cCurImage
      NumPut(ImageCount, Data + 6, "Short")                 ; cMaxImage
      NumPut(0, Data + 8, "Short")                          ; cGrow
      NumPut(Width, Data + 10, "Short")                     ; cx
      NumPut(Height // ImageCount, Data + 12, "Short")      ; cy
      NumPut(BkColor, Data + 14, "UInt")                    ; bkcolor
      NumPut(BitCount, Data + 18, "Short")                  ; flags
      NumPut(-1, Data + 20, "Int64")                        ; ovls[4]
      ; ---------------------------------------------------------------
      DllCall("GlobalUnlock", "Ptr", Data)
      DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", HGlobal, "Int", 1, "PtrP", IStream, "UInt")
      HIL := DllCall("ImageList_Read", "Ptr", IStream, "UPtr")
      ObjRelease(IStream)
      DllCall("GlobalFree", "Ptr", HGlobal)
   }
   Return HIL
}
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: Pre-built ImageLists - credits to SKAN

28 Dec 2017, 11:00

Yep, that works great, thank you! :)
Here's the entire styles library, so you can test more thoroughly with other images. Thing is, the retrieval of images and restoring of header is done by the resource tool (in my case ResHacker 4.5.30) so in theory there's room for discrepancies when different tools (or versions) are used.
Windows 7 ROSE.7z
(128.23 KiB) Downloaded 74 times
Part of my AHK work can be found here.
rodemp
Posts: 44
Joined: 15 Nov 2016, 00:28

Re: Pre-built ImageLists - credits to SKAN

19 Oct 2018, 03:08

Did you make it IL_Save to text? Using something like Base64Dec

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: IfThenElse and 138 guests