I am trying to load an application's icon(s) using the LoadImage
WinAPI function, but for some reason it always returns 0.
I have read the documentation, but I cannot understand what I've done wrong. I get no exceptions except for when trying to convert IconPtr
to Icon
(which is becasue IconPtr
is 0).
Public Shared Function ExtractAssociatedIconArray(ByVal File As String, ByVal Sizes() As Size) As Icon()
Dim ReturnArray(Sizes.Length) As Icon
Dim Index As Integer = 0
For Each s As Size In Sizes
'IconPtr is always zero for some reason.
Dim IconPtr As IntPtr = NativeMethods.LoadImage(Nothing, File, NativeMethods.Enumrations.IMAGE_ICON, s.Width, s.Height, NativeMethods.Enumrations.LR_DEFAULTCOLOR Or NativeMethods.Enumrations.LR_LOADFROMFILE)
ReturnArray(Index) = Icon.FromHandle(IconPtr)
Index += 1
Next
Return ReturnArray
End Function
The NativeMethods
class:
Public Class NativeMethods
<DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function LoadImage(ByVal hInst As IntPtr, _
ByVal lpszName As String,
ByVal uType As UInt32, _
ByVal cxDesired As Integer, _
ByVal cyDesired As Integer, _
ByVal fuLoad As UInt32) As IntPtr
End Function
Public Enum Enumrations As UInteger
'' LoadImage ''
IMAGE_BITMAP = 0
IMAGE_ICON = 1
IMAGE_CURSOR = 2
LR_CREATEDIBSECTION = &H2000
LR_DEFAULTCOLOR = &H0
LR_DEFAULTSIZE = &H40
LR_LOADFROMFILE = &H10
LR_LOADMAP3DCOLORS = &H1000
LR_LOADTRANSPARENT = &H20
LR_MONOCHROME = &H1
LR_SHARED = &H8000
LR_VGACOLOR = &H80
End Enum
End Class
Usage example:
Dim Icons() As Icon = ExtractAssociatedIconArray("C:\MyApp.exe", New Size() {New Size() {48, 48}})
You are going about this the wrong way. You are passing an executable file name to the lpszName
argument of LoadImage
. That parameter does not accept an executable file name. It accepts the name of the resource within the module specified by the first parameter, hinst
. This is explained in the documentation.
You note that you are not encountering exceptions. That's to be expected. The Win32 API won't raise exceptions. Again the documentation describes how errors are reported. They are reported by the return value being NULL
. And when that occurs, you call GetLastError
to obtain an error code. That would be Marshal.GetLastWin32Error
from .net.
To do what you are attempting using LoadImage
you need to do the following:
- Obtain an instance handle by calling
LoadLibraryEx
passing the executable file name. Use theLOAD_LIBRARY_AS_DATAFILE
flag, as described by the documentation. - Pass that instance handle to
LoadImage
. You will also need to know the name of the image resource that you wish to extract. - If you don't know the name of the resource, you'll need to use the resource enumeration functions, e.g.
EnumResourceNames
. You are looking for the first resource in the executable.
Thanks for your help and suggestions.
I managed to solve my own problem by using the ExtractIconEx
function instead.
Public Shared Function ExtractAssociatedIcons(ByVal File As String) As AssemblyIconCollection
Dim IconCount As Integer = NativeMethods.ExtractIconEx(File, -1, Nothing, Nothing, 0)
Dim AssemblyIcons As New AssemblyIconCollection
'The 'Icon handle' arrays.
Dim LargeIcons(IconCount) As IntPtr
Dim SmallIcons(IconCount) As IntPtr
'Extract icons into the two arrays of handles.
NativeMethods.ExtractIconEx(File, 0, LargeIcons, SmallIcons, IconCount)
'Add each large icon to the "LargeIcons" list.
For Each ptr As IntPtr In LargeIcons
If ptr = IntPtr.Zero Then Continue For
Dim Ico As Icon = Icon.FromHandle(ptr)
If Ico.Width < 25 Or Ico.Height < 25 Then Continue For
AssemblyIcons.LargeIcons.Add(Ico)
Next
'Add each small icon to the "SmallIcons" list.
For Each ptr As IntPtr In SmallIcons
If ptr = IntPtr.Zero Then Continue For
Dim Ico As Icon = Icon.FromHandle(ptr)
If Ico.Width > 24 Or Ico.Height > 24 Then Continue For
AssemblyIcons.SmallIcons.Add(Ico)
Next
'Return the output class.
Return AssemblyIcons
End Function
My AssemblyIconCollection
class:
Public NotInheritable Class AssemblyIconCollection
''' <summary>
''' Gets or sets the large icons found in the assembly.
''' </summary>
''' <remarks></remarks>
Public Property LargeIcons As List(Of Icon)
''' <summary>
''' Gets or sets the small icons found in the assembly.
''' </summary>
''' <remarks></remarks>
Public Property SmallIcons As List(Of Icon)
Public Sub New()
Me.LargeIcons = New List(Of Icon)
Me.SmallIcons = New List(Of Icon)
End Sub
End Class
And the ExtractIconEx
declaration:
Public Class NativeMethods
<DllImport("shell32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function ExtractIconEx(ByVal szFileName As String, _
ByVal nIconIndex As Integer, _
ByVal phiconLarge() As IntPtr, _
ByVal phiconSmall() As IntPtr, _
ByVal nIcons As UInteger) As UInteger
End Function
End Class
Usage:
Dim Icons As AssemblyIconCollection = ExtractAssociatedIcons("C:\myfile.exe")
'Iterating every large icon.
For Each LargeIcon As Icon In Icons.LargeIcons
'Do stuff.
Next
'Iterating every small icon.
For Each SmallIcon As Icon In Icons.SmallIcons
'Do stuff.
Next
来源:https://stackoverflow.com/questions/32606715/trying-to-load-an-applications-icons-using-loadimage-but-the-function-return