GetSysImgLstIcon()

Post your working scripts, libraries and tools
just me
Posts: 7222
Joined: 02 Oct 2013, 08:51
Location: Germany

GetSysImgLstIcon()

14 Dec 2013, 04:52

As requested :arrow: here this function will retrieve the associated icon for the given file path or extension and the given size from the shell's system image list (if any).

GetSysImgLstIcon.ahk:

Code: Select all

; ======================================================================================================================
; GetSysImgLstIcon() - Retrieves an icon from the system image list.
; Author:      just me
; AHK version: 1.1.13.01
; Tested on:   Win XP x86 / Win 7 x64
; Parameters:
;     Path     -  File path (max. 260 characters) or extension (including the leading dot).     (String)
;     Size     -  One of the keys defined in SHIL.                                              (String)
;                 Default: "SYSSMALL"
;     Overlay  -  Include the specified overlay icon (one of the keys defined in SHGIOI).       (String)
;                 Default: "" (none)
; Return values:
;     On success: Object containing three key/value pairs:
;                 -  HICON -  icon handle
;                 -  W     -  width in pixels
;                 -  H     -  height in pixels
;     On failure: False
; Change History:
;     1.0.02.00/2013-01-15/just me     -  replaced interface calls by image list function calls,
;                                      -  added parameter Overlay,
;                                      -  changed GetIcon flags.
;     1.0.01.00/2013-01-14/just me     -  fixed file handling.
;     1.0.00.00/2013-01-14/just me     -  initial release.
; MSDN:
;     SHGetFileInfo           -> http://msdn.microsoft.com/en-us/library/bb762179(v=vs.85).aspx
;     SHGetImageList          -> http://msdn.microsoft.com/en-us/library/bb762185(v=vs.85).aspx
;     SHGetIconOverlayIndex   -> http://msdn.microsoft.com/en-us/library/bb762183(v=vs.85).aspx
;     IIDFromString           -> http://msdn.microsoft.com/en-us/library/ms687262(v=vs.85).aspx
; ======================================================================================================================
GetSysImgLstIcon(Path, Size := "SYSSMALL", Overlay := "") {
   Static AW := A_IsUnicode ? "W" : "A"
   Static cbSFI := A_PtrSize + 8 + (340 << !!A_IsUnicode)
   Static FILE_ATTRIBUTE_NORMAL := 0x80
   Static IID_IIL_Str := "{46EB5926-582E-4017-9FDF-E8998DAA0950}"
   Static SHGFI := {SYSICONINDEX: 0x04000, USEFILEATTRIBUTES: 0x0010}
   Static SHGIOI := {SHARE: 0x0FFFFFFF, LINK: 0x0FFFFFFE, SLOWFILE: 0x0FFFFFFD, DEFAULT: 0x0FFFFFFC}
   Static SHIL := {LARGE: 0x00, SMALL: 0x01, EXTRALARGE: 0x02, SYSSMALL: 0x03, JUMBO: 0x04}
   If !SHIL.HasKey(Size)
      Return False
   VarSetCapacity(IID_IIL, 16, 0) ; IID
   If DllCall("Ole32.dll\IIDFromString", "WStr", IID_IIL_Str, "Ptr", &IID_IIL, "UInt")
      Return False
   HMOD := DllCall("Kernel32.dll\GetModuleHandle", "Str", "shell32.dll", "UPtr")
   FileIconInit := DllCall("Kernel32.dll\GetProcAddress", "Ptr", HMOD, "Ptr", 660, "UPtr")
   DllCall(FileIconInit, "UInt", True, "UInt")
   VarSetCapacity(SFI, cbSFI, 0) ; SHFILEINFO
   ; pure extensions need special handling
   Flags := SHGFI.SYSICONINDEX | (SubStr(Path, 1, 1) = "." ? SHGFI.USEFILEATTRIBUTES : 0x0)
   If !DllCall("Shell32.dll\SHGetFileInfo" . AW, "Str", Path, "UInt", 0x80, "Ptr", &SFI, "UInt", cbSFI, "UInt", Flags, "UPtr")
      Return False
   IconIndex := NumGet(SFI, A_PtrSize, "Int")
   If DllCall("Shell32.dll\SHGetImageList", "Int", SHIL[Size], "Ptr", &IID_IIL, "PtrP", IIL, "UInt")
      Return False
   Flags := 0x0020 ; ILD_IMAGE
   ; overlays need a special handling
   If SHGIOI.HasKey(Overlay)
   && (IOV := DllCall("Shell32.dll\SHGetIconOverlayIndex", "Ptr", 0, "UInt", SHGIOI[Overlay], "Int")) >= 0
      Flags |= IOV << 8
   DllCall("Comctl32.dll\ImageList_GetIconSize", "Ptr", IIL, "IntP", CX, "IntP", CY, "UInt")
   HICON := DllCall("Comctl32.dll\ImageList_GetIcon", "Ptr", IIL, "Int", IconIndex, "UInt", Flags, "UPtr")
   Return {HICON: HICON, W: CX, H: CY}
}
Sample:

Code: Select all

#NoEnv
SetBatchLines, -1
SHIL := {LARGE: 0x00, SMALL: 0x01, EXTRALARGE: 0x02, SYSSMALL: 0x03, JUMBO: 0x04}
SS_ICON := 0x03
STM_SETICON := 0x0170
Path := ".doc"
For Size, Value In SHIL {
   If !IsObject(Icon := GetSysImgLstIcon(Path, Size)) {
      MsgBox, 16, Error - %Size%, No icon found for path`r`n%Path%!
      Continue
   }
   Gui, +LastFound
   Gui, Margin, 20, 20
   IW := Icon.W, IH := Icon.H
   Gui, Add, Text, xm, Path:`t%Path%`r`nSize;`t%Size%`r`nWidth:`t%IW%`r`nHeight:`t%IH%
   Gui, Add, Pic, w%IW% h%IH% +%SS_ICON% hwndHSTATIC
   SendMessage, %STM_SETICON%, % Icon.HICON, 0, , ahk_id %HSTATIC%
   Gui, Add, Button, Default gGuiClose, Exit
   Gui, Show, w296, ShellGetIcon
   WinWaitClose
}
ExitApp
GuiClose:
   Gui, Destroy
Return
GuiEscape:
ExitApp
#Include GetSysImgLstIcon.ahk
Last edited by just me on 15 Dec 2013, 04:52, edited 2 times in total.
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: GetSysImgLstIcon()

14 Dec 2013, 06:15

Hello just me,

Great function Image

How about shortcuts (.lnk) and folders (and their associated icons, if any)?
just me
Posts: 7222
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GetSysImgLstIcon()

14 Dec 2013, 08:56

Hello Chef,

thank you for asking. The function did not handle files and folders correctly. It should work better now!
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: GetSysImgLstIcon()

14 Dec 2013, 11:10

A better testing GUI...

Code: Select all

#NoEnv
#Persistent
#SingleInstance force
SetWorkingDir %A_ScriptDir%
SetBatchLines, -1


test_folder := "C:\Windows"
SHIL := {LARGE: 0x00, SMALL: 0x01, EXTRALARGE: 0x02, SYSSMALL: 0x03, JUMBO: 0x04}

gui, +lastFound
For Size, Value in SHIL
	gui, add, radio, xm y+10 vCtrl_%size% gDEMO, %size%
guicontrol,, JUMBO,1
gui, add, edit, x+50 ym w1000 vEdit, %test_folder%
gui,add, listview, xp y+10 wp h600 vlv hWNDhlv Icon 0x100 +0x100, Item
gui,add, button,x0 y0 w0 h0 +default gDEMO
gui,add, statusBar
sB_setparts(200,200)
sB_setText("Drag-n-drop")
gosub, DEMO
gui, show,, GetSysImgLstIcon_DEMO
return

DEMO:
	gui, submit,noHide
	For Size, Value in SHIL
		if ctrl_%size%
		{
			size := size
			break
		}
	lv_load( edit )
	return
	
guiDropFiles:
	guicontrol,,edit, %a_guiEvent%
	lv_load( a_guiEvent )
	return

lv_load( p_path )
{
	global
	lV_delete()
	il_destroy(imageList_ID)

	getSize := GetSysImgLstIcon( "C:\Windows\explorer.exe", Size )
	sB_setText(getSize.W " x " getSize.H, 2)
	imageList_ID := DllCall("comctl32.dll\ImageList_Create","int",getSize.W,"int",getSize.H,"uint",0x21,"int",10,"int", 10)
	LV_SetImageList(imageList_ID, 0)
	LV_SetImageList(imageList_ID, 1)

	guicontrol,-redraw, lv
	Loop, % (D := InStr(FileExist(p_path), "D")) ? p_path "\*.*" : p_path ,% D ? 1 : 0
	{
		If !IsObject(Icon := GetSysImgLstIcon( a_loopfilelongpath, Size))
			Continue
		idx := DllCall("ImageList_ReplaceIcon", "uint", imageList_ID, "uint",-1, "uint", Icon.HICON)+1
		lv_add("icon" idx, a_loopfilename)
	}
	guicontrol,+redraw, lv
}
	
guiclose:
	exitapp

#include, %A_ScriptDir%\GetSysImgLstIcon.ahk
I found a couple of issues so far

-JUMBO size needs some work as you can see...
Image

-(.lnk) shortcuts don't have the shortcut overlay.
-Small icons in big size appear in the top left corner, can they be centered?
Image
just me
Posts: 7222
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GetSysImgLstIcon()

14 Dec 2013, 12:12

JUMBO size needs some work as you can see...
That's not an issue of the function, it's an issue of the ListView.
(.lnk) shortcuts don't have the shortcut overlay.
Hmm, might be possible to get the overlay icon, but not with one HICON handle.
Small icons in big size appear in the top left corner, can they be centered?
This is exactly what is returned as one icon in JUMBO size (256x256).
User avatar
Chef
Posts: 50
Joined: 14 Nov 2013, 13:01

Re: GetSysImgLstIcon()

14 Dec 2013, 12:50

The chopping issue can also be seen in your test GUI...

Image
just me
Posts: 7222
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GetSysImgLstIcon()

15 Dec 2013, 05:04

Well, I've made some progress, but if you want to imitate the shell explorer completely, you'll have to unravel some more mysteries.
  • The chopping issue seems to be solved by using ILD_IMAGE (0x20) in the GetIcon flags.
  • You may add an overlay image passing the appropriate value in the added parameter 'Overlay', but you will notice, that the overlays are drawn bigger than explorer does.
  • I've still no idea, how explorer centers icons smaller than the icon image list icon dimensions.
*Updated GetSysImgLstIcon.ahk*

Return to “Scripts and Functions”

Who is online

Users browsing this forum: leosouza85, mabohango and 20 guests