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

拟墨画扇 提交于 2019-12-02 09:52:44

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:

  1. Obtain an instance handle by calling LoadLibraryEx passing the executable file name. Use the LOAD_LIBRARY_AS_DATAFILE flag, as described by the documentation.
  2. Pass that instance handle to LoadImage. You will also need to know the name of the image resource that you wish to extract.
  3. 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!