Page 1 of 1

Icons by file extension (?)

Posted: Wed Nov 10, 2021 10:07 am
by AZJIO
1. If I make the chm file first in the list, it will get an icon.
2. If there is a comma in the path to the icon, the path parser will not work. But I don't want to complicate the code.
3. Any ideas to improve the code?

Code: Select all

EnableExplicit

#ASSOCSTR_DEFAULTICON = 15
#ASSOCF_NONE = 0

Structure Icons
	Ext.s
	hIcon.i
EndStructure

Define NewList FilesLst.s()
Define NewList IconsLst.Icons()
Define LenStr = #MAX_PATH
Define AssIcon$ = Space(LenStr)
Define tmp$, Pos, hIcon
Define path.String, Ext$, isNotFind = 1
path\s = Space(#MAX_PATH)
ExtractIconEx_("Shell32.dll", 0, 0, @hIcon, 1)
AddElement(IconsLst())
IconsLst()\hIcon = hIcon
IconsLst()\Ext = ""

Define Count, a
#Tree = 0
#btn = 1


AddElement(FilesLst())
FilesLst() = "image.gif"
AddElement(FilesLst())
FilesLst() = "image.gif"
AddElement(FilesLst())
FilesLst() = "image.png"
AddElement(FilesLst())
FilesLst() = "Text.txt"
AddElement(FilesLst())
FilesLst() = "Text.txt"
AddElement(FilesLst())
FilesLst() = "image.gif"
AddElement(FilesLst())
FilesLst() = "image.iso"
AddElement(FilesLst())
FilesLst() = "help.chm"
AddElement(FilesLst())
FilesLst() = "m.mp3"


If OpenWindow(0, 0, 0, 355, 300, "Tree", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	TreeGadget(#Tree, 10, 10, 260, 280, #PB_Tree_CheckBoxes | #PB_Tree_NoLines)
	ButtonGadget(#btn, 280, 10, 30, 30, "v")
	
	
	ForEach FilesLst()
		isNotFind = 1
		Ext$ = GetExtensionPart(FilesLst())
		ForEach IconsLst()
			If IconsLst()\Ext = Ext$
				isNotFind = 0
				Break
			EndIf
		Next
		If isNotFind
			tmp$ = "." + Ext$
			If AssocQueryString_(#ASSOCF_NONE, #ASSOCSTR_DEFAULTICON, @tmp$, #Null$, @AssIcon$, @LenStr) = #S_OK
				PokeS(@path\s, StringField(AssIcon$, 1, ","))
				PathFindOnPath_(@path\s, #Null)
				If FileSize(path\s) > 0 And AddElement(IconsLst())
					ExtractIconEx_(path\s, Val(StringField(AssIcon$, 2, ",")), 0, @IconsLst()\hIcon, 1)
					IconsLst()\Ext = Ext$
				Else
					SelectElement(IconsLst(), 0)
				EndIf
			Else
				SelectElement(IconsLst(), 0)
			EndIf
		EndIf
		AddGadgetItem(#Tree, -1, FilesLst(), IconsLst()\hIcon, Pos)
	Next
	
	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_Gadget
				Select EventGadget()
					Case #btn
						Count = CountGadgetItems(#Tree)
						For a = Count - 1 To 0 Step -1
							If GetGadgetItemState(#Tree, a) & #PB_Tree_Checked
								SetGadgetItemText(#Tree, a, "* Delete")
							EndIf
						Next
				EndSelect
			Case #PB_Event_CloseWindow
				CloseWindow(0)
				End
		EndSelect
	ForEver
EndIf

Re: Icons by file extension (?)

Posted: Wed Nov 10, 2021 3:54 pm
by fryquez

Code: Select all

Procedure GetAssocIcon(sFile.s)
  Protected psfi.SHFILEINFO, IID_IImageList.clsid, IImageList.IImageList, hIcon
  SHGetFileInfo_(@sFile, #FILE_ATTRIBUTE_NORMAL, @psfi, SizeOf(SHFILEINFO), #SHGFI_USEFILEATTRIBUTES | #SHGFI_TYPENAME | #SHGFI_SYSICONINDEX)
  CLSIDFromString_("{46EB5926-582E-4017-9FDF-E8998DAA0950}", @IID_IImageList)
  #SHIL_SYSSMALL = 3
  If SHGetImageList_(#SHIL_SYSSMALL, @IID_IImageList, @IImageList) = #S_OK
    IImageList\GetIcon(psfi\iIcon, 0, @hicon)
    IImageList\Release()
  EndIf  
  ProcedureReturn hicon
EndProcedure

;hIcon = GetAssocIcon(".gif")

Re: Icons by file extension (?)

Posted: Wed Nov 10, 2021 4:12 pm
by AZJIO
This function (SHGetFileInfo) only works with an existing file.

Re: Icons by file extension (?)

Posted: Wed Nov 10, 2021 4:36 pm
by fryquez
AZJIO wrote: Wed Nov 10, 2021 4:12 pm This function (SHGetFileInfo) only works with an existing file.
Says who?

Re: Icons by file extension (?)

Posted: Wed Nov 10, 2021 7:33 pm
by STARGÅTE
AZJIO wrote: Wed Nov 10, 2021 4:12 pm This function (SHGetFileInfo) only works with an existing file.
No it doesn't.

Code: Select all


Enumeration
	#ExtensionIcon_Small
	#ExtensionIcon_Large
EndEnumeration

Procedure.i GetExtensionIcon(FileName.s, Size.i=#ExtensionIcon_Small) 
	
	Protected FileInfo.SHFILEINFO, Flags.i = #SHGFI_ICON | #SHGFI_USEFILEATTRIBUTES
	
	Select Size
		Case #ExtensionIcon_Small : Flags | #SHGFI_SMALLICON
		Case #ExtensionIcon_Large : Flags | #SHGFI_LARGEICON 
	EndSelect 
	
	If SHGetFileInfo_(@FileName, #FILE_ATTRIBUTE_NORMAL, @FileInfo, SizeOf(SHFILEINFO), Flags) 
		ProcedureReturn FileInfo\hIcon 
	Else
		ProcedureReturn #False
	EndIf 
	
EndProcedure


Enumeration
	#Window
	#Gadget
EndEnumeration

OpenWindow(#Window, 0, 0, 400, 300, "Vector Canvas Gadget", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window), #PB_Canvas_Keyboard)

If StartDrawing(CanvasOutput(#Gadget))
	DrawImage(GetExtensionIcon(".png", #ExtensionIcon_Large), 5, 5)
	DrawImage(GetExtensionIcon(".pdf", #ExtensionIcon_Large), 45, 5)
	DrawImage(GetExtensionIcon(".exe", #ExtensionIcon_Large), 85, 5)
	StopDrawing()
EndIf


Repeat
	
	Select WaitWindowEvent()
		
		Case #PB_Event_CloseWindow
			Break
		
	EndSelect
	
ForEver

End

Re: Icons by file extension (?)

Posted: Thu Nov 11, 2021 1:44 am
by BarryG
Thanks for the example, STARGÅTE.

Just for the record, when I used to get icons from extensions in the (very distant) past, it never worked without a valid file for me either, so I had to create a dummy file in %TEMP% to get the icon. Not sure when this got changed by Microsoft.

Re: Icons by file extension (?)

Posted: Thu Nov 11, 2021 5:43 am
by AZJIO
STARGÅTE
Thanks

The problem is solved, but why if the counter is increased to 900 or more, then the code gives an error? If icons are not used, then there are no problems.

Code: Select all

	For i = 0 To 6000
		AddGadgetItem(#Tree, -1, "folder "+Str(i), 0, 0)
		AddGadgetItem(#Tree, -1, "Sub.chm", 0, 1)
		AddGadgetItem(#Tree, -1, "Sub.gif", 0,  1)
		AddGadgetItem(#Tree, -1, "Sub.mp3", 0, 1)
		AddGadgetItem(#Tree, -1, "Sub.avi", 0, 1)
		AddGadgetItem(#Tree, -1, "File "+Str(i), 0, 1)
	Next
-

Code: Select all

EnableExplicit


Define tmp$, hIcon, hIcon2, htree, StartTime
ExtractIconEx_("Shell32.dll", 4, 0, @hIcon, 1)
ExtractIconEx_("Shell32.dll", 0, 0, @hIcon2, 1)

Define i, Count
#Tree = 0
#btn = 1

Enumeration
	#ExtensionIcon_Small
	#ExtensionIcon_Large
EndEnumeration

Procedure.i GetExtensionIcon(FileName.s, Size.i=#ExtensionIcon_Small) 
	
	Protected FileInfo.SHFILEINFO, Flags.i = #SHGFI_ICON | #SHGFI_USEFILEATTRIBUTES
	
	Select Size
		Case #ExtensionIcon_Small : Flags | #SHGFI_SMALLICON
		Case #ExtensionIcon_Large : Flags | #SHGFI_LARGEICON 
	EndSelect 
	
	If SHGetFileInfo_(@FileName, #FILE_ATTRIBUTE_NORMAL, @FileInfo, SizeOf(SHFILEINFO), Flags) 
		ProcedureReturn FileInfo\hIcon 
	Else
		ProcedureReturn #False
	EndIf 
	
EndProcedure

If OpenWindow(0, 0, 0, 355, 600, "Tree", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	htree = TreeGadget(#Tree, 10, 10, 260, 580, #PB_Tree_CheckBoxes | #PB_Tree_NoLines)
	ButtonGadget(#btn, 280, 10, 30, 30, "v")
	
	StartTime=ElapsedMilliseconds()
; 	htree = GadgetID(#Tree)
	SendMessage_(htree, #WM_SETREDRAW, 0, 0)
	For i = 0 To 470
		AddGadgetItem(#Tree, -1, "folder "+Str(i), hIcon, 0)
		AddGadgetItem(#Tree, -1, "file.chm", GetExtensionIcon(".chm"), 1)
		AddGadgetItem(#Tree, -1, "file.gif",  GetExtensionIcon(".gif"), 1)
		AddGadgetItem(#Tree, -1, "file.png",  GetExtensionIcon(".png"), 1)
		AddGadgetItem(#Tree, -1, "file.txt",  GetExtensionIcon(".txt"), 1)
		AddGadgetItem(#Tree, -1, "file.mp3",  GetExtensionIcon(".mp3"), 1)
		AddGadgetItem(#Tree, -1, "file.avi",  GetExtensionIcon(".avi"), 1)
		AddGadgetItem(#Tree, -1, "file.iso",  GetExtensionIcon(".iso"), 1)
		AddGadgetItem(#Tree, -1, "file",  hIcon2, 1)
	Next
	SendMessage_(htree, #WM_SETREDRAW, 1, 0)
	; 	SendMessage_(WindowID(0), #WM_SETREDRAW, 1, 1)
	tmp$ = Str(ElapsedMilliseconds()-StartTime) + " ms"
	Count = CountGadgetItems(#Tree)
	SetWindowTitle(#Tree , "count=" +Str(Count) + ", time=" + tmp$)
	
	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_Gadget
				Select EventGadget()
					Case #btn
						Count = CountGadgetItems(#Tree)
						For i = Count - 1 To 0 Step -1
							If GetGadgetItemState(#Tree, i) & #PB_Tree_Checked
								SetGadgetItemText(#Tree, i, "* Delete")
							EndIf
						Next
				EndSelect
			Case #PB_Event_CloseWindow
				CloseWindow(0)
				End
		EndSelect
	ForEver
EndIf

Re: Icons by file extension (?)

Posted: Thu Nov 11, 2021 5:06 pm
by fryquez
PB's AddGadgetItem() will always add a new icon to the treeview's attached image list.
Thus the size will increase and properly hit a limit at some time.

You will need to handle the image list your self as every usable file manager does.

Make a copy of the system image list and assign it to your treeview.
Use my example with SHGFI_SYSICONINDEX to get index and then skip PB's AddGadgetItem() and go all API to handle treeview.

Re: Icons by file extension (?)

Posted: Thu Nov 11, 2021 5:35 pm
by AZJIO
fryquez
Your example throws the error "SHGetImageList is not a function".

When I use 2 icons for a file and for a folder, there is no problem.
Does the tree create as many icons as there are items in the tree? Then there would be a failure with 2 icons. I tried to use the icon cache, as in the first example, but it didn't help and the program worked a little slower. I have full confidence that the SHGetFileInfo function uses the same cache as the explorer. That is, the function does not return a new handle for identical icons.

Do you propose to do it entirely on WinAPI?

Re: Icons by file extension (?)

Posted: Fri Nov 12, 2021 10:57 pm
by AZJIO
I reverted the AssocQueryString feature as I have no problem with any number of files.