Page 1 of 1
Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sat May 09, 2020 9:39 am
by tatanas
Hi,
Here is a way to extract an icon from a resource file (dll/exe) at the size you desire and use it with an image gadget (the function returns an icon handle so an imageID in PB) :
Code: Select all
; Macro LOWORD(dwValue) : dwValue & $FFFF : EndMacro
; Macro HIWORD(dwValue) : dwValue >> 16 : EndMacro
Prototype.i Proto_SHDefExtractIcon(pszIconFile.s, iIndex.i, uFlags.i, phiconLarge.i, phiconSmall.i, nIconSize.i)
Procedure ExtractArbitrarySizeIcon(pszPath.s, index, size)
Protected hIcon
OpenLibrary(0, "Shell32.dll")
Protected SHDefExtractIcon_.Proto_SHDefExtractIcon = GetFunction(0, "SHDefExtractIconW")
If SHDefExtractIcon_(pszPath, index, 0, @hIcon, #Null, size) = #S_OK
ProcedureReturn hIcon
EndIf
ProcedureReturn 0
EndProcedure
If OpenWindow(0, 0, 0, 300, 50, "ImageGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
hicon1 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 16)
ImageGadget(1, 0, 0, 50, 50, hicon1)
hicon2 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 24)
ImageGadget(2, 50, 0, 50, 50, hicon2)
hicon3 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 32)
ImageGadget(3, 100, 0, 50, 50, hicon3)
hicon4 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 40)
ImageGadget(4, 150, 0, 50, 50, hicon4)
hicon5 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 48)
ImageGadget(5, 200, 0, 50, 50, hicon5)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
DestroyIcon_(hicon1)
DestroyIcon_(hicon2)
DestroyIcon_(hicon3)
DestroyIcon_(hicon4)
DestroyIcon_(hicon5)
Msdn doc :
https://docs.microsoft.com/en-us/window ... tracticonw
The doc doesn't match my experience. It seems you can use only the phiconLarge pointer to get every size you want...
Re: Extract Icon from Dll/exe at non standard size
Posted: Sat May 09, 2020 1:07 pm
by FlatEarth
Nice, thanks for sharing.
Re: Extract Icon from Dll/exe at non standard size
Posted: Sun May 10, 2020 12:50 pm
by blueb
I've been using some older 2013 code by 'Nalor' which still works well and you might fine useful.
see:
https://www.purebasic.fr/english/viewto ... 43#p417143
Re: Extract Icon from Dll/exe at non standard size(WINDOWS O
Posted: Sun May 10, 2020 6:22 pm
by Kwai chang caine
Works fine here, thanks for sharing

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sat Oct 09, 2021 5:12 am
by BarryG
Thanks tatanas - I was looking for this today!
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sat Oct 09, 2021 6:31 am
by Denis
Thanks tatanas, i discover this API.
I was working a lot about Icons, but even today, I don't clearly understand the difference between the small and large icons.
Any Idea?
i've tested your code with small Icon and it seems to works. I don't know if it will works with all Icon of all files.
I still don't understand what is the difference with small or large Icon with this API.
With your code modified a bit, I've extracted an icon 128x128 because it doesn't exist into the file.
The code modified to get icon from small Icon, hope i use this API correctly ...
Code: Select all
; Macro LOWORD(dwValue) : dwValue & $FFFF : EndMacro
; Macro HIWORD(dwValue) : dwValue >> 16 : EndMacro
Prototype.i Proto_SHDefExtractIcon(pszIconFile.s, iIndex.i, uFlags.i, phiconLarge.i, phiconSmall.i, nIconSize.i)
Procedure ExtractArbitrarySizeIcon(pszPath.s, index, size)
Protected hIcon
OpenLibrary(0, "Shell32.dll")
Protected SHDefExtractIcon_.Proto_SHDefExtractIcon = GetFunction(0, "SHDefExtractIconW")
; If SHDefExtractIcon_(pszPath, index, 0, @hIcon, #Null, size) = #S_OK
; ProcedureReturn hIcon
; EndIf
size << 16 ; HIWORD of size.
If SHDefExtractIcon_(pszPath, index, 0, #Null, @hIcon, size) = #S_OK
ProcedureReturn hIcon
EndIf
ProcedureReturn 0
EndProcedure
If OpenWindow(0, 0, 0, 400, 200, "ImageGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
hicon1 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 16)
ImageGadget(1, 0, 0, 50, 50, hicon1)
hicon2 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 24)
ImageGadget(2, 50, 0, 50, 50, hicon2)
hicon3 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 32)
ImageGadget(3, 100, 0, 50, 50, hicon3)
hicon4 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 40)
ImageGadget(4, 150, 0, 50, 50, hicon4)
hicon5 = ExtractArbitrarySizeIcon("c:\windows\system32\shell32.dll", 22, 128)
ImageGadget(5, 200, 0, 50, 50, hicon5)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
DestroyIcon_(hicon1)
DestroyIcon_(hicon2)
DestroyIcon_(hicon3)
DestroyIcon_(hicon4)
DestroyIcon_(hicon5)
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sun Oct 10, 2021 3:51 am
by BarryG
Can someone with Windows 7 please run the below code and confirm if you get the same icon as in my screenshot?
Also, if your icon is different, could you please post a screenshot so I can see what it is. Thanks!
Code: Select all
Prototype.i Proto_SHDefExtractIcon(pszIconFile.s,iIndex.i,uFlags.i,phiconLarge.i,phiconSmall.i,nIconSize.i)
Procedure IconExtractFromFile(file$,index,size=16)
lib=OpenLibrary(#PB_Any,"shell32.dll")
If lib
SHDefExtractIcon_.Proto_SHDefExtractIcon=GetFunction(lib,"SHDefExtractIconW")
If SHDefExtractIcon_(file$,index,0,@hIcon,0,size)=#S_OK
ok=hIcon
EndIf
CloseLibrary(lib)
EndIf
ProcedureReturn ok
EndProcedure
If OpenWindow(0,0,0,100,100,"test",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
hicon1 = IconExtractFromFile("c:\windows\system32\explorer.exe",8,16)
ImageGadget(1,55,40,50,50,hicon1)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
DestroyIcon_(hicon1)
EndIf
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sun Oct 10, 2021 6:22 am
by Paul
BarryG wrote: Sun Oct 10, 2021 3:51 am
Also, if your icon is different, could you please post a screenshot so I can see what it is. Thanks!
On my copy of Windows 7, Explorer.exe is not in System32 folder, it's in the main Windows folder and your code extracts this icon...

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Sun Oct 10, 2021 6:48 am
by BarryG
Thanks Paul, I'll ditch that idea then. Trying to get a generic Windows icon from a system file, but that's proving to be difficult. Can't include one with my app because it's copyrighted to Microsoft, so extracting it during runtime from somewhere was my plan.
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 1:53 pm
by ChrisR
Extracting the icon at runtime was however a good idea
It was just the path that was not good, explorer.exe is in windows folder (%WINDIR%) in all windows versions.
A small addition to the procedure to pass only the filename or possibly correct the path, if the filename exists in %Path%
Code: Select all
Prototype.i Proto_SHDefExtractIcon(pszIconFile.s,iIndex.i,uFlags.i,phiconLarge.i,phiconSmall.i,nIconSize.i)
Procedure IconExtractFromFile(file$,index,size=16)
If Not PathFileExists_(@file$)
file$ = GetFilePart(file$)
*buf=AllocateMemory(#MAX_PATH)
PokeS(*buf,file$)
PathFindOnPath_(*buf, #Null)
file$=PeekS(*buf)
FreeMemory(*buf)
EndIf
If PathFileExists_(@file$)
lib=OpenLibrary(#PB_Any,"shell32.dll")
If lib
SHDefExtractIcon_.Proto_SHDefExtractIcon=GetFunction(lib,"SHDefExtractIconW")
If SHDefExtractIcon_(file$,index,0,@hIcon,0,size)=#S_OK
ok=hIcon
EndIf
CloseLibrary(lib)
EndIf
ProcedureReturn ok
EndIf
EndProcedure
Define Path$
;Path$ = "c:\windows\system32\explorer.exe"
;Path$ = GetEnvironmentVariable("WINDIR") + "\Explorer.exe"
Path$ = "Explorer.exe"
If OpenWindow(0,0,0,100,100,"test",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
hicon1 = IconExtractFromFile(Path$,-205,16)
ImageGadget(1,55,40,50,50,hicon1)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
DestroyIcon_(hicon1)
EndIf
Edit: With Paul's addition below
fryquez wrote: Mon Oct 11, 2021 3:58 pm
PathFindOnPath_() expects a bigger buffer than it get's.
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 3:28 pm
by Paul
@ ChrisR
On my Windows 10 machine your code works fine but on Windows 7 it just crashes.
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 3:58 pm
by fryquez
PathFindOnPath_() expects a bigger buffer than it get's.
Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 4:27 pm
by Paul
fryquez wrote: Mon Oct 11, 2021 3:58 pm
PathFindOnPath_() expects a bigger buffer than it get's.
Ah, you are right. If I change this part I no longer get a crash...
Code: Select all
If Not PathFileExists_(@file$)
file$ = GetFilePart(file$)
*buf=AllocateMemory(#MAX_PATH)
PokeS(*buf,file$)
PathFindOnPath_(*buf, #Null)
file$=PeekS(*buf)
FreeMemory(*buf)
EndIf
Unfortunately the results on Windows 7 are exactly the same as the code by BarryG

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 5:11 pm
by RASHAD
The problem with BarryG code is the icon number
Windows 10,11 icon 8
Windows 7,8.x icon 10
It's MS after all

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)
Posted: Mon Oct 11, 2021 5:26 pm
by ChrisR
Indeed it works better with the right buffer size, thanks fryquez
I just tried it with Paul's addition with windows 7 in VMware and I get the same result.
I checked with
IconsExtract, under windows 7, the 8th icon is the exclamation mark. The computer icon is the 10th.
So not the same position of the icon in explorer file as in windows 10.
It's probably better to use the icon's resource ID, using its negative value: hicon1 = IconExtractFromFile(Path$,-205,16)
Edit: RASHAD was faster
