extracticon api using vba (in Word or Excel)

T

Terry Hornsby

I would like to be able to extract all the icons from a file and:

(a) graphically show them in a form (as a kind of list array)
(b) export the icons to a folder
(c) select individual icons on this form for use as toolbar buttons

Can this be done?

I have tried adapting the extracticon & drawicon apis from a vbnet site, but
can't get the extracted icon(s) to show on the form or do anything else with
them, & as (c) derives from (a) & (b) I'm stuck!

And I can't figure out what the vba equivalents are! Can anyone please help?
 
H

Helmut Weber

Hi Terry,
why api at all?
I would like to be able to extract all the icons from a file and:
Really? From just 1 file or from any file? The second would mean to
check any (!) file for possibly contained icons, and to extract them.
A program namend Microangelo did that. May be, it is still available.
But anyway, a program that extracts all icons from all files on a 400
GB Server and stores them in seperate files in an icon-folder would be
of no help, if the icons weren't classified at the same time according
to there possible meaning.
(b) export the icons to a folder
What would that be good for? Wouldn't it be sufficient, to store icons
and FaceIDs in an Excel-Sheet or a in a table in a Word-File?
And I can't figure out what the vba equivalents are!
If you are talking about any icon in any file, there might be no
VBA equivalent at all.
Collecting faces of icons and the VBA-IDs is not that difficult.
A very, very limited demo using the commandbar "Standard" to show
the principles:
(It is assumed, that there is a "1 row 2 column table".)

Dim c As CommandBar
Dim l As Long
Dim s As String
Dim t As Table
Set t = ActiveDocument.Tables(1)
Set c = CommandBars("Standard")
For l = 1 To c.Controls.Count
c.Controls.Item(l).CopyFace
s = CStr(c.Controls.Item(l).FaceId)
t.Cell(l, 1).Select
Selection.Paste
t.Cell(l, 2).Select
Selection.TypeText Text:=s
t.Rows.Add ' a once redundant empty row
Next
Greetings from Bavaria, Germany
Helmut Weber
"red.sys" & chr$(64) & "t-online.de"
Word XP, Win 98
 
T

Terry Hornsby

How can I use the EXTRACTICON & DRAWICONS apis within vba to: -

(1) extract icons from files
hIcon = ExtractIcon(0&, sIconFile, cnt)
appears to work, but as DRAWICON doesn't seem to do anything, I'm none the
wiser.

(2) paste the icon images to a userform. My attempt to adapt the call
doesn't work:
Call DrawIcon(Me.Img1.Height, rowX, colX, hIcon)
original code:
Call DrawIcon(Picture1.hdc, x, Y, hIcon)
doesn't work either because image controls on userforms do not have a "hdc"
property. I'm assuming this is 'height'. ("hicon" would appear to be the
pointer to the actual icon).

(3) Export the extracted icons to a file or copy them to a button face (in
other words, how do I get the code to recognise I have selected an .ico file
from the form or by looping thru code?).

The api calls I'm making are: -

Private Declare Function DrawIcon Lib "user32" _

(ByVal hdc As Long, _

ByVal x As Long, _

ByVal Y As Long, _

ByVal hIcon As Long) As Long



Private Declare Function ExtractIcon Lib "shell32" _

Alias "ExtractIconA" _

(ByVal hInst As Long, _

ByVal lpszExeFileName As String, _

ByVal nIconIndex As Long) As Long



Private Declare Function DestroyIcon Lib "user32" _

(ByVal hIcon As Long) As Long



Is it just that I should be using command buttons (& button faces) rather
than trying to pull the images into an image control as you can do with
picture controls in vb.net?

---------------------------------------------------



This bit is just to respond to Helmut: -

The ExtractIcon method is exactly what I meant.

I already have: -

(1) several routines & utilities to get the button faces & face ids from
Office applications;

(2) an api based browse for folder/file routine from which I can pick a file
to examine for hidden .ico files. I have no intention of extracting ALL
icons willy-nilly into any file;

(3) a third party utility to extract icons. I am aware of Microangelo. I
don't need it; &

(4) a utility to convert .ico files to .bmp files & to import these as
button faces on command bar buttons*.

*I find storing the icons this way (in a folder) means that I have a well of
images I can readily use to create my own office toolbars with distinctive &
possibly more meaningful button faces than those available from the built-in
faces for Office.

For example, if I wanted a commandbar button to call a non-office
application, wouldn't it be neat to have that application's icon as the
button face? Wouldn't it be a drag to have to write reams of code every time
I wanted to do that, when I can simply use a browse for file form & extract
whatever icon I wanted whenever I wanted?

Using Apis within vba is entirely possible, Helmut, & if you are to presume
to help people with problems like this you should at least be aware that the
functionality is there.

The reasons for wanting to use apis directly are: (a) no additional
overheads going through the scripting or shell libraries (b) Most of my code
aleady calls many of the api functions EXTRACTICON also uses, so there would
be unnecessary redundancy using scripting; (c) I believe it's marginally
quicker using apis directly (d) I don't have to set a reference to the other
libraries in my utility, which makes it more user-friendly, more portable.

I am aware that calling these apis from within vba is possible, I have 95%
of the code worked out to do it.

So, my original questions still stand.

Many thanks, however, for giving it a go.

Best wishes,

Terry.
 
L

Lars-Eric Gisslén

Terry,

When you Win API to do the drawing you must allways draw to the device
context, never mind if the context is a printer driver or a Window (even a
control is a Window). So, you must get the device context for the Window to
draw the icon on. You normally don't draw an Icon in a control but on the
Windows/dialogs surface. To get the device context for your Dialog (Form in
VBA) you should be able to it by calling the WinAPI function
GetActiveWindow. With handle returned you acn get the handle to the device
context by calling GetDC() Win API function.

The code below shows how I draw an Icon on a dialog but from a different
development tool. I guess you can convert the code to VBA and make it
working: Replace the SELF:Handle() with the handle returned from
GetActiveWindow()

METHOD Expose() CLASS YesNoAllBox
//s Call Back method that is called when the Window needs to be repainted
//l The Icon set in code, or default Icon, will be painted in the method
//r NIL, nothing to return

LOCAL hIcon AS PTR
LOCAL hDC AS PTR

SUPER:Expose()

IF SELF:MessageIcon <> NULL_PTR // Load Icon, if any
hIcon := LoadIcon(0, SELF:MessageIcon) // Load a default Windows Icon
hDC := GetDC(SELF:Handle()) // Get the Device Context of the Dialog
DrawIcon(hDC, 20, 20, hIcon) // Paint the Icon on the surface at fixed
possition
ReleaseDC(SELF:Handle(), hDC) // Device Contexts must always be released
hIcon := NULL_PTR
ENDIF

RETURN NIL
 
T

Terry Hornsby

Lars-Eric,

Many thanks for the help.

I'll take a close look later & see if I can adapt the example you gave.



Best wishes,

Terry.
 
T

Terry Hornsby

Lars-Eric,

Your help was very much appreciated. By pasting in the two extra api
functions & amending the DrawIcon code to this:

Call DrawIcon(GetWindowDC(GetActiveWindow), rowX, colX,
hIcon)

The rest of the code worked & I got a nice neat row of icons on my form -
except for one thing - the icons were ON my form (top left) instead of
pasted into the image control on the form. I've had a look through the api
index to see how I can get a hook on the image control, but no luck, unless
SENDMESSAGE is the api I need for a callback to the drawicon api, but it
isn't clear.

Can anyone help with this bit?!

Best,


Terry.
 
L

Lars-Eric Gisslén

Terry,

I would not use nested calls like you do. GetWindowDC returns the DC for the
entire Window while GetDC returns the DC of the client area where the
drawing should actually take place. Plus, DC's should always be relesed with
ReleaseDC(). The way you have coded it you have lost the handle to the DC
and can not release it when you are done. Your code will propably lead to
memory leakage.

To find the correct control to draw in I think you will need some trial and
error. I would suggest you get the handle to the Window and use it in a call
to EnumChildWindows(). Create a callback function that is called from the
EnumChildWindow. In the callback function can try to use call GetWindowText
to get the caption of the control or using SendMessage() with some of the
WM_GET... parameters and to get some meaningful value from the control that
indentifies it.

What you also have think about is the redrawing the Icons. If you open
another application that covers your dialog you must find a way to trigger
when your dialog is uncovered so you can redraw the icons. As you use WinAPI
calls to draw the Icons you are responsible for redrawing them when needed.
In my code example I had my code in a Method called Expose and that method
is always called when a Windows needs to be repainted, fully or partial. I
don't know if you can trigger that in VBA.

I'm not so familiar with VBA forms so I can tell what to actually do, just
give some hints. I'm not even a VB programmer so I'm a little bit lost when
it comes to deaper VB/VBA programming. My dev tool let's me take full
control over every thing, when I want to, even the event handling at
application level.
 
T

Terry Hornsby

Lars-Eric,

Many thanks for all the help you've given. I took a look at enumchildwindows
& knew that the activewindows wasn't right. I even looked at GetWindowText &
had the vague notion I'd have to use one or more of them, but it's like
having pieces of a jigsaw & not knowing how they go together!

The tips you gave are certainly useful, because at least I know now WHAT api
calls to look at & how they can work together to get what I want. The
copyicon & bit-thingy apis might be useful later on, too. Finally, releasedc
& avoiding nesting is NOT something I had looked at, so those tips in
themselves are gold-dust.

Many thanks,

Terry.

P.S I might be able to use a repaint or refresh on the image if needed.
Alternatively, I might simply try to assign the images to commandbuttons &
kill two-birds with one stone (ie, clicking it will paste the image over to
whatever toolbar I want to create).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top