【问题标题】:Trying to load an application's icon(s) using LoadImage, but the function returns 0尝试使用 LoadImage 加载应用程序的图标,但函数返回 0
【发布时间】:2015-09-16 10:59:12
【问题描述】:

我正在尝试使用LoadImage WinAPI 函数加载应用程序的图标,但由于某种原因它总是返回 0。

我已经阅读了documentation,但我无法理解我做错了什么。除了尝试将IconPtr 转换为Icon(这是因为IconPtr 为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

NativeMethods 类:

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

使用示例:

Dim Icons() As Icon = ExtractAssociatedIconArray("C:\MyApp.exe", New Size() {New Size() {48, 48}})

【问题讨论】:

  • 从文档(甚至从方法的名称)来看,返回的句柄似乎与图像相关联,而不是与图标相关联。您是否尝试过将输出转换为图像/位图(并将此变量转换为图标)?
  • 一个EXE文件通常包含多个图标。请注意您从未指定过您想要哪一个。这也不是特别容易找到的,图标资源 ID 是任意的。所以你只是使用了错误的 winapi 函数来完成工作。请改用 Icon.ExtractAssociatedIcon()。
  • @varocarbas : 这无关紧要,因为无论哪种方式,函数都会返回 0。
  • @HansPassant :我在一个 SO 答案中读到 LoadImage 将获得最接近您指定大小的图标/图像。不幸的是,我目前没有该答案的链接。

标签: vb.net winapi icons native-methods


【解决方案1】:

您以错误的方式处理此问题。您将一个可执行文件名传递给LoadImagelpszName 参数。该参数不接受可执行文件名。它接受第一个参数hinst 指定的模块内的资源名称。这在文档中进行了解释。

您注意到您没有遇到异常。这是可以预料的。 Win32 API 不会引发异常。文档再次描述了如何报告错误。它们由返回值为NULL 报告。发生这种情况时,您调用GetLastError 以获取错误代码。那将是来自 .net 的 Marshal.GetLastWin32Error

要使用LoadImage 执行您尝试的操作,您需要执行以下操作:

  1. 通过调用LoadLibraryEx 传递可执行文件名来获取实例句柄。如文档所述,使用 LOAD_LIBRARY_AS_DATAFILE 标志。
  2. 将该实例句柄传递给LoadImage。您还需要知道要提取的图像资源的名称。
  3. 如果您不知道资源的名称,则需要使用资源枚举函数,例如EnumResourceNames。您正在寻找可执行文件中的第一个资源。

【讨论】:

  • 哦...所以我误解了文档:)。我会看看你的建议。从 .exe 中提取所需大小的图标很困难,是吗? (:
  • @VisualVincent:这并不难,只是乏味。 Icons 拥有您需要的所有信息(图标 API:原始资源字节)。要查找所需大小的图标 ID,请致电LookupIconIdFromDirectory,并手动构建图标。或者改用CreateIconFromResourceEx
  • 非常感谢您的帮助。我设法使用ExtractIconEx 解决了它。不过,你教会了我一些有价值的东西。 :)
【解决方案2】:

感谢您的帮助和建议。

我设法改用ExtractIconEx 函数解决了我自己的问题。

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

我的AssemblyIconCollection 班级:

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

还有ExtractIconEx 声明:

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

用法:

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

【讨论】:

    猜你喜欢
    • 2017-02-03
    • 2020-11-26
    • 1970-01-01
    • 2023-03-15
    • 2020-01-28
    • 2017-09-16
    • 1970-01-01
    • 2014-01-02
    相关资源
    最近更新 更多