Mapped.IconExtractor

This commit is contained in:
2023-01-02 14:35:59 +01:00
parent 8dbd0a764e
commit 3c49701873
7 changed files with 359 additions and 4 deletions

View File

@@ -1,5 +1,7 @@
Imports System.Drawing Imports System.Drawing
Imports System.Runtime.InteropServices Imports System.Runtime.InteropServices
Imports Pilz.Win32.Mapped
Imports Pilz.Win32.Native Imports Pilz.Win32.Native
Namespace Internals Namespace Internals
@@ -10,10 +12,11 @@ Namespace Internals
''' Extrahiert das Icon aus einer Datei oder aus einem Ordner. ''' Extrahiert das Icon aus einer Datei oder aus einem Ordner.
''' </summary> ''' </summary>
''' <param name="FilePath">Hier übergeben Sie den Pfad der Datei von dem das Icon extrahiert werden soll.</param> ''' <param name="FilePath">Hier übergeben Sie den Pfad der Datei von dem das Icon extrahiert werden soll.</param>
''' <param name="Small">Bei übergabe von true wird ein kleines und bei false ein großes Icon zurück gegeben.</param> ''' <param name="size">Bei übergabe von true wird ein kleines und bei false ein großes Icon zurück gegeben.</param>
Public Shared Function ExtractIcon(FilePath As String, Small As Boolean) As Icon Public Shared Function ExtractIcon(FilePath As String, size As SystemIconSize) As Icon
Dim icon As Icon Dim icon As Icon
Dim shinfo As New SHFILEINFO Dim shinfo As New SHFILEINFO
Dim small As Boolean = size = SystemIconSize.Small
LibShell32.SHGetFileInfo(FilePath, 0, shinfo, Math.Truncate(Marshal.SizeOf(shinfo)), SHFILEINFO.SHGFI_ICON Or If(Small, SHFILEINFO.SHGFI_SMALLICON, SHFILEINFO.SHGFI_LARGEICON)) LibShell32.SHGetFileInfo(FilePath, 0, shinfo, Math.Truncate(Marshal.SizeOf(shinfo)), SHFILEINFO.SHGFI_ICON Or If(Small, SHFILEINFO.SHGFI_SMALLICON, SHFILEINFO.SHGFI_LARGEICON))

View File

@@ -0,0 +1,208 @@
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.Reflection
Imports System.Collections.Generic
Imports System.Drawing
Imports Pilz.Win32.Native
Imports Pilz.Win32.Native.Shell32
Imports Pilz.Win32.Mapped
Namespace Internals
Public Class IconFactory
#Region "Custom exceptions class"
Public Class IconNotFoundException
Inherits Exception
Public Sub New(ByVal fileName As String, ByVal index As Integer)
MyBase.New(String.Format("Icon with Id = {0} wasn't found in file {1}", index, fileName))
End Sub
End Class
Public Class UnableToExtractIconsException
Inherits Exception
Public Sub New(ByVal fileName As String, ByVal firstIconIndex As Integer, ByVal iconCount As Integer)
MyBase.New(String.Format("Tryed to extract {2} icons starting from the one with id {1} from the ""{0}"" file but failed", fileName, firstIconIndex, iconCount))
End Sub
End Class
#End Region
''' <summary>
''' Get the number of icons in the specified file.
''' </summary>
''' <param name="fileName">Full path of the file to look for.</param>
''' <returns></returns>
Private Shared Function GetIconsCountInFile(fileName As String) As Integer
Return ExtractIconEx(fileName, -1, Nothing, Nothing, 0)
End Function
#Region "ExtractIcon-like functions"
Public Shared Sub ExtractEx(ByVal fileName As String, ByVal largeIcons As List(Of Icon), ByVal smallIcons As List(Of Icon), ByVal firstIconIndex As Integer, ByVal iconCount As Integer)
'
' Memory allocations
'
Dim smallIconsPtrs As IntPtr() = Nothing
Dim largeIconsPtrs As IntPtr() = Nothing
If smallIcons IsNot Nothing Then
smallIconsPtrs = New IntPtr(iconCount - 1) {}
End If
If largeIcons IsNot Nothing Then
largeIconsPtrs = New IntPtr(iconCount - 1) {}
End If
'
' Call to native Win32 API
'
Dim apiResult = ExtractIconEx(fileName, firstIconIndex, largeIconsPtrs, smallIconsPtrs, iconCount)
If apiResult <> iconCount Then
Throw New UnableToExtractIconsException(fileName, firstIconIndex, iconCount)
End If
'
' Fill lists
'
If smallIcons IsNot Nothing Then
smallIcons.Clear()
For Each actualIconPtr In smallIconsPtrs
smallIcons.Add(Icon.FromHandle(actualIconPtr))
Next
End If
If largeIcons IsNot Nothing Then
largeIcons.Clear()
For Each actualIconPtr In largeIconsPtrs
largeIcons.Add(Icon.FromHandle(actualIconPtr))
Next
End If
End Sub
Public Shared Function ExtractEx(ByVal fileName As String, ByVal size As SystemIconSize, ByVal firstIconIndex As Integer, ByVal iconCount As Integer) As List(Of Icon)
Dim iconList As New List(Of Icon)()
Select Case size
Case SystemIconSize.Large
ExtractEx(fileName, iconList, Nothing, firstIconIndex, iconCount)
Case SystemIconSize.Small
ExtractEx(fileName, Nothing, iconList, firstIconIndex, iconCount)
Case Else
Throw New ArgumentOutOfRangeException("size")
End Select
Return iconList
End Function
Public Shared Sub Extract(ByVal fileName As String, ByVal largeIcons As List(Of Icon), ByVal smallIcons As List(Of Icon))
Dim iconCount = GetIconsCountInFile(fileName)
ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount)
End Sub
Public Shared Function Extract(ByVal fileName As String, ByVal size As SystemIconSize) As List(Of Icon)
Dim iconCount = GetIconsCountInFile(fileName)
Return ExtractEx(fileName, size, 0, iconCount)
End Function
Public Shared Function ExtractOne(ByVal fileName As String, ByVal index As Integer, ByVal size As SystemIconSize) As Icon
Try
Dim iconList = ExtractEx(fileName, size, index, 1)
Return iconList(0)
Catch __unusedUnableToExtractIconsException1__ As UnableToExtractIconsException
Throw New IconNotFoundException(fileName, index)
End Try
End Function
Public shared Sub ExtractOne(ByVal fileName As String, ByVal index As Integer, <Out> ByRef largeIcon As Icon, <Out> ByRef smallIcon As Icon)
Dim smallIconList As List(Of Icon) = New List(Of Icon)()
Dim largeIconList As List(Of Icon) = New List(Of Icon)()
Try
ExtractEx(fileName, largeIconList, smallIconList, index, 1)
largeIcon = largeIconList(0)
smallIcon = smallIconList(0)
Catch __unusedUnableToExtractIconsException1__ As UnableToExtractIconsException
Throw New IconNotFoundException(fileName, index)
End Try
End Sub
#End Region
'this will look throw the registry
'to find if the Extension have an icon.
Public Shared Function IconFromExtension(ByVal extension As String, ByVal size As SystemIconSize) As Icon
' Add the '.' to the extension if needed
If extension(0) <> "."c Then extension = "."c & extension
'opens the registry for the wanted key.
Dim Root = Registry.ClassesRoot
Dim ExtensionKey = Root.OpenSubKey(extension)
ExtensionKey.GetValueNames()
Dim ApplicationKey As RegistryKey = Root.OpenSubKey(ExtensionKey.GetValue("").ToString())
'gets the name of the file that have the icon.
Dim IconLocation As String = ApplicationKey.OpenSubKey("DefaultIcon").GetValue("").ToString()
Dim IconPath = IconLocation.Split(","c)
If Equals(IconPath(1), Nothing) Then IconPath(1) = "0"
Dim Large = New IntPtr(0) {}, Small = New IntPtr(0) {}
'extracts the icon from the file.
ExtractIconEx(IconPath(0), Convert.ToInt16(IconPath(1)), Large, Small, 1)
Return If(size = SystemIconSize.Large, Icon.FromHandle(Large(0)), Icon.FromHandle(Small(0)))
End Function
Public Shared Function IconFromExtensionShell(ByVal extension As String, ByVal size As SystemIconSize) As Icon
'add '.' if nessesry
If extension(0) <> "."c Then extension = "."c & extension
'temp struct for getting file shell info
Dim fileInfo As SHFILEINFO = New SHFILEINFO()
SHGetFileInfo(extension, 0, fileInfo, Marshal.SizeOf(fileInfo), FileInfoFlags.SHGFI_ICON Or FileInfoFlags.SHGFI_USEFILEATTRIBUTES Or CType(size, FileInfoFlags))
Return Icon.FromHandle(fileInfo.hIcon)
End Function
Public Shared Function IconFromResource(ByVal resourceName As String) As Icon
Dim assembly As Assembly = Assembly.GetCallingAssembly()
Return New Icon(assembly.GetManifestResourceStream(resourceName))
End Function
''' <summary>
''' Parse strings in registry who contains the name of the icon and
''' the index of the icon an return both parts.
''' </summary>
''' <param name="regString">The full string in the form "path,index" as found in registry.</param>
''' <param name="fileName">The "path" part of the string.</param>
''' <param name="index">The "index" part of the string.</param>
Public Shared Sub ExtractInformationsFromRegistryString(ByVal regString As String, <Out> ByRef fileName As String, <Out> ByRef index As Integer)
If Equals(regString, Nothing) Then
Throw New ArgumentNullException("regString")
End If
If regString.Length = 0 Then
Throw New ArgumentException("The string should not be empty.", "regString")
End If
index = 0
Dim strArr = regString.Replace("""", "").Split(","c)
fileName = strArr(0).Trim()
If strArr.Length > 1 Then
Call Integer.TryParse(strArr(1).Trim(), index)
End If
End Sub
Public Shared Function ExtractFromRegistryString(ByVal regString As String, ByVal size As SystemIconSize) As Icon
Dim fileName As String
Dim index As Integer
ExtractInformationsFromRegistryString(regString, fileName, index)
Return ExtractOne(fileName, index, size)
End Function
End Class
End Namespace

View File

@@ -0,0 +1,17 @@
Imports System.Drawing
Namespace Mapped
Public Module IconExtractor
Public Function ExtractIconFromFilePath(filePath As String, size As SystemIconSize) As Icon
Return Internals.IconExtractor.ExtractIcon(filePath, size)
End Function
Public Function ExtractIconFromFileExtension(fileExtension As String, size As SystemIconSize)
Return Internals.IconFactory.IconFromExtensionShell(fileExtension, size)
End Function
End Module
End Namespace

View File

@@ -0,0 +1,12 @@
Namespace Mapped
''' <summary>
''' Two constants extracted from the FileInfoFlags, the only that are
''' meaningfull for the user of this class.
''' </summary>
Public Enum SystemIconSize As Integer
Large
Small
End Enum
End Namespace

View File

@@ -0,0 +1,20 @@
Namespace Native
<Flags>
Public Enum FileInfoFlags As Integer
''' <summary>
''' Retrieve the handle to the icon that represents the file and the index
''' of the icon within the system image list. The handle is copied to the
''' hIcon member of the structure specified by psfi, and the index is copied
''' to the iIcon member.
''' </summary>
SHGFI_ICON = &H100
''' <summary>
''' Indicates that the function should not attempt to access the file
''' specified by pszPath. Rather, it should act as if the file specified by
''' pszPath exists with the file attributes passed in dwFileAttributes.
''' </summary>
SHGFI_USEFILEATTRIBUTES = &H10
End Enum
End Namespace

View File

@@ -2,18 +2,43 @@
Namespace Native Namespace Native
''' <summary>
''' Contains information about a file object.
''' </summary>
<StructLayout(LayoutKind.Sequential)> <StructLayout(LayoutKind.Sequential)>
Public Structure SHFILEINFO Public Structure SHFILEINFO
Public Const SHGFI_ICON As UInteger = &H100 Public Const SHGFI_ICON As UInteger = &H100
Public Const SHGFI_LARGEICON As UInteger = &H0 Public Const SHGFI_LARGEICON As UInteger = &H0
Public Const SHGFI_SMALLICON As UInteger = &H1 Public Const SHGFI_SMALLICON As UInteger = &H1
''' <summary>
''' Handle to the icon that represents the file. You are responsible for
''' destroying this handle with DestroyIcon when you no longer need it.
''' </summary>
Public hIcon As IntPtr Public hIcon As IntPtr
''' <summary>
''' Index of the icon image within the system image list.
''' </summary>
Public iIcon As IntPtr Public iIcon As IntPtr
''' <summary>
''' Array of values that indicates the attributes of the file object.
''' For information about these values, see the IShellFolder::GetAttributesOf
''' method.
''' </summary>
Public dwAttributes As UInteger Public dwAttributes As UInteger
''' <summary>
''' String that contains the name of the file as it appears in the Microsoft
''' Windows Shell, or the path and file name of the file that contains the
''' icon representing the file.
''' </summary>
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)>
Public szDisplayName As String Public szDisplayName As String
''' <summary>
''' String that describes the type of file.
''' </summary>
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)>
Public szTypeName As String Public szTypeName As String
End Structure End Structure

View File

@@ -0,0 +1,70 @@
Imports System.Runtime.InteropServices
Namespace Native
Public Class Shell32
''' <summary>
''' Creates an array of handles to large or small icons extracted from
''' the specified executable file, dynamic-link library (DLL), or icon
''' file.
''' </summary>
''' <param name="lpszFile">
''' Name of an executable file, DLL, or icon file from which icons will
''' be extracted.
''' </param>
''' <param name="nIconIndex">
''' <para>
''' Specifies the zero-based index of the first icon to extract. For
''' example, if this value is zero, the function extracts the first
''' icon in the specified file.
''' </para>
''' <para>
''' If this value is <20>1 and <paramrefname="phiconLarge"/> and
''' <paramrefname="phiconSmall"/> are both NULL, the function returns
''' the total number of icons in the specified file. If the file is an
''' executable file or DLL, the return value is the number of
''' RT_GROUP_ICON resources. If the file is an .ico file, the return
''' value is 1.
''' </para>
''' <para>
''' Windows 95/98/Me, Windows NT 4.0 and later: If this value is a
''' negative number and either <paramrefname="phiconLarge"/> or
''' <paramrefname="phiconSmall"/> is not NULL, the function begins by
''' extracting the icon whose resource identifier is equal to the
''' absolute value of <paramrefname="nIconIndex"/>. For example, use -3
''' to extract the icon whose resource identifier is 3.
''' </para>
''' </param>
''' <param name="phIconLarge">
''' An array of icon handles that receives handles to the large icons
''' extracted from the file. If this parameter is NULL, no large icons
''' are extracted from the file.
''' </param>
''' <param name="phIconSmall">
''' An array of icon handles that receives handles to the small icons
''' extracted from the file. If this parameter is NULL, no small icons
''' are extracted from the file.
''' </param>
''' <param name="nIcons">
''' Specifies the number of icons to extract from the file.
''' </param>
''' <returns>
''' If the <paramrefname="nIconIndex"/> parameter is -1, the
''' <paramrefname="phIconLarge"/> parameter is NULL, and the
''' <paramrefname="phiconSmall"/> parameter is NULL, then the return
''' value is the number of icons contained in the specified file.
''' Otherwise, the return value is the number of icons successfully
''' extracted from the file.
''' </returns>
<DllImport("Shell32", CharSet:=CharSet.Auto)>
Public Shared Function ExtractIconEx(<MarshalAs(UnmanagedType.LPTStr)> ByVal lpszFile As String, ByVal nIconIndex As Integer, ByVal phIconLarge As IntPtr(), ByVal phIconSmall As IntPtr(), ByVal nIcons As Integer) As Integer
End Function
<DllImport("Shell32", CharSet:=CharSet.Auto)>
Public Shared Function SHGetFileInfo(ByVal pszPath As String, ByVal dwFileAttributes As Integer, <Out> ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As FileInfoFlags) As IntPtr
End Function
End Class
End Namespace