尝试使用 LoadImage 加载应用程序的图标,但函数 returns 0
Trying to load an application's icon(s) using LoadImage, but the function returns 0
我正在尝试使用 LoadImage
WinAPI 函数加载应用程序的图标,但由于某些原因它总是 returns 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
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
用法示例:
Dim Icons() As Icon = ExtractAssociatedIconArray("C:\MyApp.exe", New Size() {New Size() {48, 48}})
你的做法是错误的。您正在将可执行文件名传递给 LoadImage
的 lpszName
参数。该参数不接受可执行文件名。它接受第一个参数 hinst
指定的模块内的资源名称。这在文档中有解释。
您注意到您没有遇到异常。这是可以预料的。 Win32 API 不会引发异常。文档再次描述了如何报告错误。它们的 return 值为 NULL
。当发生这种情况时,您调用 GetLastError
以获得错误代码。那将是来自 .net 的 Marshal.GetLastWin32Error
。
要使用 LoadImage
执行您尝试的操作,您需要执行以下操作:
- 通过调用
LoadLibraryEx
传递可执行文件名来获取实例句柄。使用 LOAD_LIBRARY_AS_DATAFILE
标志,如文档所述。
- 将该实例句柄传递给
LoadImage
。您还需要知道要提取的图像资源的名称。
- 如果您不知道资源名称,则需要使用资源枚举函数,例如
EnumResourceNames
。您正在寻找可执行文件中的第一个资源。
感谢您的帮助和建议。
我改用 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
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
和 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
我正在尝试使用 LoadImage
WinAPI 函数加载应用程序的图标,但由于某些原因它总是 returns 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
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
用法示例:
Dim Icons() As Icon = ExtractAssociatedIconArray("C:\MyApp.exe", New Size() {New Size() {48, 48}})
你的做法是错误的。您正在将可执行文件名传递给 LoadImage
的 lpszName
参数。该参数不接受可执行文件名。它接受第一个参数 hinst
指定的模块内的资源名称。这在文档中有解释。
您注意到您没有遇到异常。这是可以预料的。 Win32 API 不会引发异常。文档再次描述了如何报告错误。它们的 return 值为 NULL
。当发生这种情况时,您调用 GetLastError
以获得错误代码。那将是来自 .net 的 Marshal.GetLastWin32Error
。
要使用 LoadImage
执行您尝试的操作,您需要执行以下操作:
- 通过调用
LoadLibraryEx
传递可执行文件名来获取实例句柄。使用LOAD_LIBRARY_AS_DATAFILE
标志,如文档所述。 - 将该实例句柄传递给
LoadImage
。您还需要知道要提取的图像资源的名称。 - 如果您不知道资源名称,则需要使用资源枚举函数,例如
EnumResourceNames
。您正在寻找可执行文件中的第一个资源。
感谢您的帮助和建议。
我改用 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
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
和 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