Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Share your advanced PureBasic knowledge/code with the community.
tatanas
Enthusiast
Enthusiast
Posts: 186
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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...
Windows 10 Pro x64
PureBasic 6.03 x64
FlatEarth

Re: Extract Icon from Dll/exe at non standard size

Post by FlatEarth »

Nice, thanks for sharing.
User avatar
blueb
Addict
Addict
Posts: 1037
Joined: Sat Apr 26, 2003 2:15 pm
Location: Cuernavaca, Mexico

Re: Extract Icon from Dll/exe at non standard size

Post 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
- It was too lonely at the top.

System : PB 6.10 Beta 7 (x64) and Win Pro 11 (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Extract Icon from Dll/exe at non standard size(WINDOWS O

Post by Kwai chang caine »

Works fine here, thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
BarryG
Addict
Addict
Posts: 3266
Joined: Thu Apr 18, 2019 8:17 am

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post by BarryG »

Thanks tatanas - I was looking for this today!
Denis
Enthusiast
Enthusiast
Posts: 703
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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)
A+
Denis
BarryG
Addict
Addict
Posts: 3266
Joined: Thu Apr 18, 2019 8:17 am

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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!

Image

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
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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...

Image
Image Image
BarryG
Addict
Addict
Posts: 3266
Joined: Thu Apr 18, 2019 8:17 am

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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.
User avatar
ChrisR
Addict
Addict
Posts: 1124
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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.
Last edited by ChrisR on Mon Oct 11, 2021 5:31 pm, edited 2 times in total.
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post by Paul »

@ ChrisR

On my Windows 10 machine your code works fine but on Windows 7 it just crashes.
Image Image
fryquez
Enthusiast
Enthusiast
Posts: 359
Joined: Mon Dec 21, 2015 8:12 pm

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post by fryquez »

PathFindOnPath_() expects a bigger buffer than it get's.
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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
Image
Image Image
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4622
Joined: Sun Apr 12, 2009 6:27 am

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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 :)
Egypt my love
User avatar
ChrisR
Addict
Addict
Posts: 1124
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Extract Icon from Dll/exe at non standard size(WINDOWS ONLY)

Post 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 :)
Post Reply