Search code examples
vb.netwinapiiconsnative-methods

Trying to load an application's icon(s) using LoadImage, but the function returns 0


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}})

Solution

  • 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