ExtractAssociatedIcon 
Author Message
 ExtractAssociatedIcon

How can I use the ExtractAssociatedIcon API to place the Associated
Icon of a file into a PictureBox or an ImageBox?  the only example I
have found:
'--------------------
Const DI_MASK = &H1
Const DI_IMAGE = &H2
Const DI_NORMAL = DI_MASK Or DI_IMAGE
Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
    Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
    ByVal lpIconPath As String, ByVal lpiIcon As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, _
    ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, _
    ByVal cxWidth As Long, ByVal cyWidth As Long, _
    ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, _
    ByVal diFlags As Long) As Long
Private Declare Function DestroyIcon Lib "user32" _
    (ByVal hIcon As Long) As Long

Private Sub Form_Paint()
    On Error Resume Next
    Dim mIcon As Long
    'Extract the associated icon
    mIcon = ExtractAssociatedIcon(App.hInstance, "C:\Autoexec.bat", 2)
    'Draw the icon on the form
    DrawIconEx Me.hdc, 0, 0, mIcon, 0, 0, 0, 0, DI_NORMAL
    'remove the icon from the memory
    DestroyIcon mIcon
End Sub
'----------------------------
But it just paints the icon onto the form.  I've tried to make it
paint to the Me.Picture1.hdc with no success.  Setting

Picture1.Picture = mIcon

or

Picture1.Image = mIcon

both give me Type Mismatch errors.....Can anyone help?

A second quick question, how do I make my program use only one
instance?

Thank you

Kevin



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
Quote:
> A second quick question, how do I make my program use only one
> instance?

Simple! App.PrevInstance returns a Boolean to if there is another program
already running under the name that the current one is named!

If App.PrevInstance = True Then
    MsgBox "Previous Instance, Quitting", vbExclamation
    End
End If

Peter



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
That example doesn't even work.  It crashes the application because the
ExtactAssociatedIconA function's lpiIcon parameter is supposed to be a
Pointer (lp), and it is supposed to be a WORD (16 bits/Integer).  Anyway,
after correcting the function declaration, I added some extra code so you
can see it paint the Icon into a Picture1 PictureBox.  The code also
requires you to now press the Command1 button to execute it (there is no
reason to waste resources calling the code for each Form_Paint if we are
going to use AutoRedraw).

Oh, and in regards to your second question, you have to Add a standard .BAS
module to your application.  Then place this code in it (modified of course
from Form1 to whatever module you want to show first):

Option Explicit

Private Sub Main()
  If Not App.PrevInstance Then Form1.Show
End Sub

And finally, click on Project [menu] -> Project1 Properties... [menu] ->
Startup Object: [combo box] and then set it to Sub Main.

Here is the revised code for the Icon gunk:

Option Explicit
Const DI_MASK = &H1
Const DI_IMAGE = &H2
Const DI_NORMAL = DI_MASK Or DI_IMAGE
Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
    Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
    ByVal lpIconPath As String, lpiIcon As Integer) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, _
    ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, _
    ByVal cxWidth As Long, ByVal cyWidth As Long, _
    ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, _
    ByVal diFlags As Long) As Long
Private Declare Function DestroyIcon Lib "user32" _
    (ByVal hIcon As Long) As Long

Private Sub Command1_Click()
  Dim mIcon As Long
  'Extract the associated icon
  mIcon = ExtractAssociatedIcon(App.hInstance, "c:\autoexec.bat", 0)
  'Setup our Picturebox and make it ready to accept the image
  Picture1.AutoRedraw = True  'Needed to it won't just disappear
  Picture1.Cls                'Needed so it will show up imediately
  'Paint the Icon into Picture1's Device Context
  DrawIconEx Picture1.hdc, 0, 0, mIcon, 0, 0, 0, 0, DI_NORMAL
  'remove the icon from the memory
  DestroyIcon mIcon
End Sub

Howard Henry Schlunder


Quote:
> How can I use the ExtractAssociatedIcon API to place the Associated
> Icon of a file into a PictureBox or an ImageBox?  the only example I
> have found:
> '--------------------
> Const DI_MASK = &H1
> Const DI_IMAGE = &H2
> Const DI_NORMAL = DI_MASK Or DI_IMAGE
> Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
>     Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
>     ByVal lpIconPath As String, ByVal lpiIcon As Long) As Long
> Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, _
>     ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, _
>     ByVal cxWidth As Long, ByVal cyWidth As Long, _
>     ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, _
>     ByVal diFlags As Long) As Long
> Private Declare Function DestroyIcon Lib "user32" _
>     (ByVal hIcon As Long) As Long

> Private Sub Form_Paint()
>     On Error Resume Next
>     Dim mIcon As Long
>     'Extract the associated icon
>     mIcon = ExtractAssociatedIcon(App.hInstance, "C:\Autoexec.bat", 2)
>     'Draw the icon on the form
>     DrawIconEx Me.hdc, 0, 0, mIcon, 0, 0, 0, 0, DI_NORMAL
>     'remove the icon from the memory
>     DestroyIcon mIcon
> End Sub
> '----------------------------
> But it just paints the icon onto the form.  I've tried to make it
> paint to the Me.Picture1.hdc with no success.  Setting

> Picture1.Picture = mIcon

> or

> Picture1.Image = mIcon

> both give me Type Mismatch errors.....Can anyone help?

> A second quick question, how do I make my program use only one
> instance?

> Thank you

> Kevin



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
That isn't what i meant.  let me lengthen the question.

ok say my program starts once by someone clicking on a file.  Then
that someone tries to open another file that my app will open.  I
don't want another instance to start, I want the previous instance to
do what the new instance would have done, i.e. open the file up in a
new MDIChild window....all I need to know is how to make my app "talk"
to the pevious instance of my app....

Thank you, Kevin


| > A second quick question, how do I make my program use only one
| > instance?
| Simple! App.PrevInstance returns a Boolean to if there is another
program
| already running under the name that the current one is named!
|
| If App.PrevInstance = True Then
|     MsgBox "Previous Instance, Quitting", vbExclamation
|     End
| End If
|
|
| Peter
|
|



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
thanks, I knew about that pointer thing, I just made a mistake, and
the only one instance thing, that is not what I meant, thanks though.
bye

Kevin



| That example doesn't even work.  It crashes the application because
the
| ExtactAssociatedIconA function's lpiIcon parameter is supposed to be
a
| Pointer (lp), and it is supposed to be a WORD (16 bits/Integer).
Anyway,
| after correcting the function declaration, I added some extra code
so you
| can see it paint the Icon into a Picture1 PictureBox.  The code also
| requires you to now press the Command1 button to execute it (there
is no
| reason to waste resources calling the code for each Form_Paint if we
are
| going to use AutoRedraw).
|
| Oh, and in regards to your second question, you have to Add a
standard .BAS
| module to your application.  Then place this code in it (modified of
course
| from Form1 to whatever module you want to show first):
|
| Option Explicit
|
| Private Sub Main()
|   If Not App.PrevInstance Then Form1.Show
| End Sub
|
| And finally, click on Project [menu] -> Project1 Properties...
[menu] ->
| Startup Object: [combo box] and then set it to Sub Main.
|
| Here is the revised code for the Icon gunk:
|
| Option Explicit
| Const DI_MASK = &H1
| Const DI_IMAGE = &H2
| Const DI_NORMAL = DI_MASK Or DI_IMAGE
| Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
|     Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
|     ByVal lpIconPath As String, lpiIcon As Integer) As Long
| Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long,
_
|     ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, _
|     ByVal cxWidth As Long, ByVal cyWidth As Long, _
|     ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, _
|     ByVal diFlags As Long) As Long
| Private Declare Function DestroyIcon Lib "user32" _
|     (ByVal hIcon As Long) As Long
|
| Private Sub Command1_Click()
|   Dim mIcon As Long
|   'Extract the associated icon
|   mIcon = ExtractAssociatedIcon(App.hInstance, "c:\autoexec.bat", 0)
|   'Setup our Picturebox and make it ready to accept the image
|   Picture1.AutoRedraw = True  'Needed to it won't just disappear
|   Picture1.Cls                'Needed so it will show up imediately
|   'Paint the Icon into Picture1's Device Context
|   DrawIconEx Picture1.hdc, 0, 0, mIcon, 0, 0, 0, 0, DI_NORMAL
|   'remove the icon from the memory
|   DestroyIcon mIcon
| End Sub
|
| Howard Henry Schlunder
|

| > How can I use the ExtractAssociatedIcon API to place the
Associated
| > Icon of a file into a PictureBox or an ImageBox?  the only example
I
| > have found:
| > '--------------------
| > Const DI_MASK = &H1
| > Const DI_IMAGE = &H2
| > Const DI_NORMAL = DI_MASK Or DI_IMAGE
| > Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
| >     Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
| >     ByVal lpIconPath As String, ByVal lpiIcon As Long) As Long
| > Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As
Long, _
| >     ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long,
_
| >     ByVal cxWidth As Long, ByVal cyWidth As Long, _
| >     ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long,
_
| >     ByVal diFlags As Long) As Long
| > Private Declare Function DestroyIcon Lib "user32" _
| >     (ByVal hIcon As Long) As Long
| >
| > Private Sub Form_Paint()
| >     On Error Resume Next
| >     Dim mIcon As Long
| >     'Extract the associated icon
| >     mIcon = ExtractAssociatedIcon(App.hInstance,
"C:\Autoexec.bat", 2)
| >     'Draw the icon on the form
| >     DrawIconEx Me.hdc, 0, 0, mIcon, 0, 0, 0, 0, DI_NORMAL
| >     'remove the icon from the memory
| >     DestroyIcon mIcon
| > End Sub
| > '----------------------------
| > But it just paints the icon onto the form.  I've tried to make it
| > paint to the Me.Picture1.hdc with no success.  Setting
| >
| > Picture1.Picture = mIcon
| >
| > or
| >
| > Picture1.Image = mIcon
| >
| > both give me Type Mismatch errors.....Can anyone help?
| >
| >
| >
| > A second quick question, how do I make my program use only one
| > instance?
| >
| >
| >
| > Thank you
| >
| > Kevin
|
|
|



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon

This isn't a very commonly asked question, and it is rather difficult to implement efficiently.  However, I have seen other people ask this question before, and I wanted to tackle the problem, so I decided to do it now.  What it does is register a WM_USER message type and then the second instance broadcasts that message when new command line parameters are given by the second process.  Since it is a non-standard VB event, it has to subclass a top level form (Form1) and then detect the message from there.  I had originally planned on placing the command string in a shared or global memory heap so that I could just CopyMemory it back into a string variable in the first process.  However, to my utter disappointment, the concept of global memory heaps has died in Win32, so my calls to GlobalAlloc and GlobalLock were futile in preventing the abundant GPFs.  Another option I looked at for sharing the command string was the CreateFileMapping API stuff.  However, since it requires a base file to play with, I thought better of creating a file just for this single command line string.  I ended up just using GetSetting and SaveSetting as a public place to transfer data between the processes.

Anyway, you, of course, will have to write the code to load the proper MDIChildren and such.   The IncommingData Sub is called whenever a second process (with command line parameters) tries to start.  To use it, just create a BAS Module, put this code in it:

Option Explicit

Public Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
Public Declare Function BroadcastSystemMessage Lib "user32" (ByVal dw As Long, pdw As Long, ByVal un As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const BSM_APPLICATIONS = &H8
Public Const BSF_IGNORECURRENTTASK = &H2
Public Const BSF_POSTMESSAGE = &H10
Public Const GWL_WNDPROC = -4

Public lpPrevWndProc As Long, gHW As Long
Public WM_OtherAppSendingDataIn As Long

Private Sub Main()
  'Register a WM_USER message for our application
  WM_OtherAppSendingDataIn = RegisterWindowMessage("Howard Henry Schlunder's unique string to register the special message with.")
  If App.PrevInstance Then  'Other app open
    If Len(Command) Then  'We have a command string to pass to the other instance
      'Save the command string to a public location (so the other process can read it)
      Call SaveSetting(App.ProductName, "General Stuff", "Latest command line parameters", Command)
      'Broadcast the message to all top level windows
      Call BroadcastSystemMessage(BSF_POSTMESSAGE Or BSF_IGNORECURRENTTASK, BSM_APPLICATIONS, WM_OtherAppSendingDataIn, 0, 0)
    End If
  Else  'No other instances, lets start up normally
    MDIForm1.Show
  End If
End Sub

Private Sub IncommingData(cmdLineParameters As String)
  MsgBox "Somebody has been executing a second process and has passed these command line parameters to us: " & cmdLineParameters
End Sub

Public Sub Hook()
   lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub

Public Sub Unhook()
   Call SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
End Sub

Public Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  If uMsg = WM_OtherAppSendingDataIn Then 'Another instance gave us some data
    Call IncommingData(GetSetting(App.ProductName, "General Stuff", "Latest command line parameters", ""))
  End If
  WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
End Function

Then change your Project Startup Object to Sub Main (if you haven't already).  Then, put this code in your MDIForm1:

Option Explicit

Private Sub MDIForm_Load()
   gHW = Me.hwnd
   Hook    'Begin subclassing
End Sub

Private Sub MDIForm_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Unhook    'Prevent undesireables
End Sub

Howard Henry Schlunder

Quote:

> That isn't what i meant.  let me lengthen the question.

> ok say my program starts once by someone clicking on a file.  Then
> that someone tries to open another file that my app will open.  I
> don't want another instance to start, I want the previous instance to
> do what the new instance would have done, i.e. open the file up in a
> new MDIChild window....all I need to know is how to make my app "talk"
> to the pevious instance of my app....

> Thank you, Kevin



> | > A second quick question, how do I make my program use only one
> | > instance?
> | Simple! App.PrevInstance returns a Boolean to if there is another
> program
> | already running under the name that the current one is named!
> |
> | If App.PrevInstance = True Then
> |     MsgBox "Previous Instance, Quitting", vbExclamation
> |     End
> | End If
> |
> |
> | Peter



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
There's probably a much easier and more documented way of doing this, but my
way would be:

Register a system message like "WM_OPENFILEINSTANCE" or something like that.
Then when you try to open a new file, it runs your app, and you have in the
loadup code something to detect that the app is already running (like
app.previnstance).  The you need to send a message to that app of
WM_OPENFILEINSTANCE or whatever, with the parameter of that filename.  The
new instance then exits.

The previous instance receives the message, the first parameter of which is
the filename.  It opens that file.

~Alex


Quote:
> That isn't what i meant.  let me lengthen the question.

> ok say my program starts once by someone clicking on a file.  Then
> that someone tries to open another file that my app will open.  I
> don't want another instance to start, I want the previous instance to
> do what the new instance would have done, i.e. open the file up in a
> new MDIChild window....all I need to know is how to make my app "talk"
> to the pevious instance of my app....

> Thank you, Kevin



> | > A second quick question, how do I make my program use only one
> | > instance?
> | Simple! App.PrevInstance returns a Boolean to if there is another
> program
> | already running under the name that the current one is named!
> |
> | If App.PrevInstance = True Then
> |     MsgBox "Previous Instance, Quitting", vbExclamation
> |     End
> | End If
> |
> |
> | Peter
> |
> |



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
With the exception of the "parameter of that filename" part, that's exactly
what my example code does.  The problem with messages is that they use a
wParam and lParam, both which are only 32 bits long.  Since a maximum string
length of 8 characters is unacceptable, it would be ideal to just put the
string in a public memory heap and send a 32 bit pointer to it.  However, as
stated, I don't think that is possible (and as of current, I have no clue
how Microsoft's Win32 API accomplishes this).

Howard Henry Schlunder


Quote:
> There's probably a much easier and more documented way of doing this, but
my
> way would be:

> Register a system message like "WM_OPENFILEINSTANCE" or something like
that.
> Then when you try to open a new file, it runs your app, and you have in
the
> loadup code something to detect that the app is already running (like
> app.previnstance).  The you need to send a message to that app of
> WM_OPENFILEINSTANCE or whatever, with the parameter of that filename.  The
> new instance then exits.

> The previous instance receives the message, the first parameter of which
is
> the filename.  It opens that file.

> ~Alex



> > That isn't what i meant.  let me lengthen the question.

> > ok say my program starts once by someone clicking on a file.  Then
> > that someone tries to open another file that my app will open.  I
> > don't want another instance to start, I want the previous instance to
> > do what the new instance would have done, i.e. open the file up in a
> > new MDIChild window....all I need to know is how to make my app "talk"
> > to the pevious instance of my app....

> > Thank you, Kevin



> > | > A second quick question, how do I make my program use only one
> > | > instance?
> > | Simple! App.PrevInstance returns a Boolean to if there is another
> > program
> > | already running under the name that the current one is named!
> > |
> > | If App.PrevInstance = True Then
> > |     MsgBox "Previous Instance, Quitting", vbExclamation
> > |     End
> > | End If
> > |
> > |
> > | Peter
> > |
> > |



Wed, 18 Jun 1902 08:00:00 GMT  
 ExtractAssociatedIcon
You could implement a DDE command for your application that loads the file
into a child window. Windows will do the rest, if you register this DDE
command under shell\open\ddeexec. For example, the registry entry for MS
Word is:




If you don't want to fiddle with the registry, you could allow a 2nd
instance of your app to start, check App.PrevInstance and if true make the
DDE connection to the previous instance to pass it the filename, then shut
the 2nd instance down.

--
RobSmith


: That isn't what i meant.  let me lengthen the question.
:
: ok say my program starts once by someone clicking on a file.  Then
: that someone tries to open another file that my app will open.  I
: don't want another instance to start, I want the previous instance to
: do what the new instance would have done, i.e. open the file up in a
: new MDIChild window....all I need to know is how to make my app "talk"
: to the pevious instance of my app....
:
:
: Thank you, Kevin
:

: | > A second quick question, how do I make my program use only one
: | > instance?
: | Simple! App.PrevInstance returns a Boolean to if there is another
: program
: | already running under the name that the current one is named!
: |
: | If App.PrevInstance = True Then
: |     MsgBox "Previous Instance, Quitting", vbExclamation
: |     End
: | End If
: |
: |
: | Peter
: |
: |
:
:



Wed, 18 Jun 1902 08:00:00 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. ExtractAssociatedIcon API Help

2. ExtractAssociatedIcon API

3. ExtractAssociatedIcon API, help needed!!!

4. Nobody knows how to use ExtractAssociatedIcon ??!!

5. how to use ExtractAssociatedIcons in VB5?

6. ExtractAssociatedIcon API call

7. EXTRACTASSOCIATEDICON - Help required ..PLS

8. ExtractAssociatedIcon

9. ExtractAssociatedIcon

10. ExtractAssociatedIcon

11. ExtractAssociatedIcon like Windows Explorer

12. ExtractAssociatedIcon API

 

 
Powered by phpBB® Forum Software