ExtractIcon?

Blitz3D Forums/Blitz3D Programming/ExtractIcon?

John Blackledge(Posted 2013) [#1]
Does anyone have a Blitz equivalent of this old C function?

hIcon = ExtractIcon(hInst, szExeName, nIconNum)

I'd like to identify an exe, extract the icon, and use it to produce an image for a toolbar.


Kryzon(Posted 2013) [#2]
This thread here has the BlitzMax equivalent: http://blitzbasic.com/Community/posts.php?topic=72899

You'll need to make DECLS for "ExtractIconA" from Shell32, and "SendMessageA" from User32 (User32 can be found wrapped here).
Remember also there's SystemProperty() to get the HWND of the window of your application.


Rroff(Posted 2013) [#3]
I've never gone back and refined it so no idea if this is a good or bad way to do it (kind of forgotten about the function) but this is what I've setup as part of the blank framework I use to start any B3D project:

Function icon()
	Local bank
	Local cut
	Local test$
	Local c
	Local temp
	Local hWnd
	Local modname$
	
	hWnd = SystemProperty("AppHWND")


	bank = CreateBank(512) ; should be sizeof the returned data block
	temp = GetModuleFileName(0,bank,512)
	
	
	cut = 0
	For c = 0 To temp-1
		test$ = test$ + Chr$(PeekByte(bank,c))
		If (PeekByte(bank,c) = 92) Then
			cut = c
		EndIf
	Next
	
	FreeBank bank
	
	modname$ = Mid$(test$,cut+2)

	icon16 = ExtractIcon(hWnd,modname$,0)

	icon32 = icon16

	temp = SendMessage(hWnd,128,0,icon16)
	temp = SendMessage(hWnd,128,1,icon32)
	
	setCvar("sys_proc",modname$,CVAR_ARCH Or CVAR_PERMA Or CVAR_READONLY)

End Function


It could probably be re-written more optimally but it seems to do the job so I've never revisisted it.


John Blackledge(Posted 2013) [#4]
Thanks, but it should be normal Blitz, not BlitzPlus or Max.

I understand ExtractIcon() and User32, but how can the resulting icon handle be used to create a bitmap?


Kryzon(Posted 2013) [#5]
Oh, I see.

That's not easy, especially if you want to support XP-style icons with alpha channels.
You can write a DLL with the GDI commands to do it, but it would require C++ experience.
Alternatively you can do it with Blitz3D by directly peeking into memory and wrapping some of the Windows API, but you need to learn how the structures are formatted in memory and that takes time.

The easiest "blitz" way to do what you want is for you to use ResourceHacker's command-line options to extract the EXE's resources (it extracts all icon groups into .ICO files that you can load).
There comes a help file with ResourceHacker:

Command Line Scripting:

All the functionality of the Resource Hacker GUI (apart from viewing resources) can be accessed from the command line without having to open Resource Hacker.

[...]

Single Commands:

[...]

-extract ExeFileName, ResourceAddress, ResourceType, ResourceName,

Each command parameter must be separated by a comma, but no comma is expected before the first parameter.

To extract all icons from MyProg.exe to MyProgIcons.rc (creating MyProgIcons.rc, Icon_1.ico, Icon_2.ico , Icon_3.ico etc...)
ResHacker.exe -extract MyProg.exe, MyProgIcons.rc, icongroup,,

*Note the blank commas in the end to extract everything instead of just one.


Use ExecFile with quote chars to extract.


Rroff(Posted 2013) [#6]
I'd have thought there is an easier way to do it using GDI API functions with just a userlib but its ages since I touched that stuff so I'd need to get my head around it again.

EDIT: Looks like you'd have to rewrite a whole load of C code to blitz for outputting the buffer from memory to do it :| and even then still requires a minimal amount of memory peeking.


John Blackledge(Posted 2013) [#7]
The original C code was:

hIcon = ExtractIcon(hInst, szExeName, nIconNum-1);
hdc = GetDC(hWnd);
if (hIcon != NULL)
{ DrawIcon(hdc,x,y,hIcon); }
ReleaseDC(hWnd,hdc);

What I need is a Blitz equivalent of DrawIcon()


Kryzon(Posted 2013) [#8]
I don't understand what's the problem John, you just have to userlib DrawIcon.

.lib "shell32.dll"

api_ExtractIcon% ( hWnd%, File$, Index% ) : "ExtractIconA"

.lib "user32.dll"

api_GetDC% ( hwnd% ) : "GetDC"
api_DrawIcon% ( hdc%, x%, y%, hIcon% ) : "DrawIcon"
api_ReleaseDC% ( hwnd%, hdc% ) : "ReleaseDC"
api_GetSystemMetrics% ( nIndex% ) : "GetSystemMetrics"

.lib "gdi32.dll"

api_CreateCompatibleDC% ( hdc% ) : "CreateCompatibleDC"
api_DeleteDC% ( hdc% ) : "DeleteDC"
api_CreateCompatibleBitmap% ( hdc%, nWidth%, nHeight% ) : "CreateCompatibleBitmap"
api_GetPixel% ( hdc%, x%, y% ) : "GetPixel"
api_SelectObject% ( hdc%, hObject% ) : "SelectObject"
api_DeleteObject% ( hObject% ) : "DeleteObject"
->
;Extract the icon.
hIcon = api_ExtractIcon( hInst, szExeName, nIconNum-1 )


;Create a GDI bitmap.
Const SM_CXICON = 11
Const SM_CYICON = 12
iconWidth = api_GetSystemMetrics( SM_CXICON )
iconHeight = api_GetSystemMetrics( SM_CYICON )
hDC = api_GetDC( 0 )
hMemDC= api_CreateCompatibleDC( hDC )
hMemBmp= api_CreateCompatibleBitmap( hDC, iconWidth, iconHeight )


;Draw the icon on the bitmap.
api_SelectObject( hMemDC, hMemBmp )
api_DrawIcon( hMemDC, 0, 0, hIcon )


;Read the bitmap's pixel data into a Blitz image.
Local blitzImage = CreateImage( iconWidth, iconHeight )
SetBuffer ImageBuffer( blitzImage )
	For x = 0 To iconWidth-1
		For y = 0 To iconHeight-1
			WritePixel( x, y, api_GetPixel( hMemDC, x, y ) )
		Next
	Next
SetBuffer BackBuffer()


;Clean all memory objects.
api_ReleaseDC( 0, hDC )
api_DeleteDC( hMemDC )
api_DeleteObject( hMemBMP )

Reference: http://www.blitzbasic.com/Community/posts.php?topic=30480#1025547


John Blackledge(Posted 2013) [#9]
Woah - very comprehensive.
Thanks Kryzon.
I'll try it in the next few days when I'm not on shift.


John Blackledge(Posted 2013) [#10]
Thanks - I've managed to simplify it even more.....

Graphics 320,160

;Extract the icon.
szExeName$ = "E:\Blitz3D\Blitz3D.exe"+Chr$(0)
hIcon = api_ExtractIcon( hInst, szExeName$, 0) : Print hIcon

;Create a GDI bitmap. - don't need it, just the icon straight to a surface
Const SM_CXICON = 11
Const SM_CYICON = 12
iconWidth = api_GetSystemMetrics( SM_CXICON )
iconHeight = api_GetSystemMetrics( SM_CYICON )
Print iconWidth+" "+iconHeight
hWnd = SystemProperty("AppHWND")  : Print hWnd
hDC = api_GetDC(hWnd) : Print hDC

While Not KeyDown(1)
	Flip
	api_DrawIcon( hDC, 75, 75, hIcon )
Wend

api_ReleaseDC( 0, hDC )
End


Thanks for all your help.


Kryzon(Posted 2013) [#11]
Good going, glad it worked.