Introduction
Every file has an icon. This icon depends on the program that can open the file in question. Obtaining these icons can be tricky, or easy, depending on the route you take. In this article, you will learn how to extract associated icons from files and display them in your programs.
I will demonstrate the different methods of extracting icons. One uses the built-in .NET Framework capabilities, and the other methods demonstrate Windows API methods.
Practical
Open Visual Studio and create a new Visual Basic Windows Forms application. On your form, add the following objects:
- Two Buttons
- One ListView
- One ImageList
Set the following properties for the ListView:
- View: SmallIcon
- SmallImageList: The name of your ImageList
Your design should look like Figure 1.
Figure 1: Design
Code
Add the following code:
Public Sub ExtractIcon_1() Dim dInfo As New System.IO.DirectoryInfo("c:\") Dim lvItem As ListViewItem ListView2.BeginUpdate() ListView2.Items.Clear() Dim CurrFile As System.IO.FileInfo For Each CurrFile In dInfo.GetFiles() Dim iFileIcon As Icon = SystemIcons.WinLogo lvItem = New ListViewItem(CurrFile.Name, 1) If Not (ImageList2.Images.ContainsKey _ (CurrFile.Extension)) Then iFileIcon = System.Drawing.Icon.ExtractAssociatedIcon _ (CurrFile.FullName) ImageList2.Images.Add(CurrFile.Extension, iFileIcon) End lvItem.ImageKey = CurrFile.Extension ListView2.Items.Add( Next CurrFile ListView2.EndUpdate() End Sub
Add the following subroutine behind the first button:
Private Sub Button1_Click(sender As Object, e As EventArgs) _ Handles Button1.Click ExtractIcon_1() End Sub
The ExtractIcon_1 sub procedure loops through each of the files in the given path, and then makes use of the System.Drawing.Icon.ExtractAssociatedIcon method to extract each icon.
Add the following namespace to allow for working with the Windows API:
Imports System.Runtime.InteropServices
Add the following Windows APIs, Structs, Enums, and Constants:
<DllImport("shell32.dll", CharSet:=CharSet.Auto)> Private Shared Function SHGetFileInfo(ByVal pszPath As String, _ ByVal dwFileAttributes As Integer, <Out> ByRef _ psfi As SHFILEINFO, ByVal cbfileInfo As UInteger, _ ByVal uFlags As SHGFI) As Integer End Function <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Private Structure SHFILEINFO Public Sub New(ByVal b As Boolean) hIcon = IntPtr.Zero iIcon = 0 dwAttributes = szDisplayName = "" szTypeName = "" End Sub Public hIcon As IntPtr Public iIcon As Integer Public dwAttributes As UInteger <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> Public szDisplayName As String <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_TYPE)> Public szTypeName As String End Structure <Flags> Enum SHGFI Icon = 256 DisplayName = 512 TypeName = 1024 Attributes = 2048 IconLocation = 4096 ExeType = 8192 SysIconIndex = 16384 LinkOverlay = 32768 Selected = 65536 Attr_Specified = 131072 LargeIcon = 0 SmallIcon = 1 OpenIcon = 2 ShellIconSize = 4 PIDL = 8 UseFileAttributes = 16 AddOverlays = 32 OverlayIndex = 64 End Enum
The SHGetFileInfo Windows API function retrieves information about a file or folder. The SHFILEINFO API structure contains information about a file object. Add the following code:
Private Function GetIcons_2(ByVal strPath As String, _ ByVal blnSmall As Boolean) As Icon Dim shInfo As SHFILEINFO = New SHFILEINFO( Dim intInfo As Integer = Marshal.SizeOf(shInfo) Dim fSettings As SHGFI If blnSmall Then fSettings = SHGFI.Icon Or SHGFI.SmallIcon Or SHGFI.UseFileAttributes _ Else fSettings = SHGFI.Icon Or SHGFI.LargeIcon Or SHGFI.UseFileAttributes SHGetFileInfo(strPath, 256, shInfo, CUInt(intInfo), _ fSettings) Return Icon.FromHandle(shInfo.hIcon) End Function Public Sub ExtractIcon_2() Dim dInfo As New System.IO.DirectoryInfo("c:\") Dim lvItem As ListViewItem ListView2.BeginUpdate() ListView2.Items.Clear() Dim CurrFile As System.IO.FileInfo For Each CurrFile In dInfo.GetFiles() Dim iFileIcon As Icon = SystemIcons.WinLogo lvItem = New ListViewItem(CurrFile.Name, 1) If Not (ImageList2.Images.ContainsKey _ (CurrFile.Extension)) Then iFileIcon = GetIcons_2(CurrFile.FullName, True) ImageList2.Images.Add(CurrFile.Extension, iFileIcon) End If lvItem.ImageKey = CurrFile.Extension ListView2.Items.Add(lvItem) Next CurrFile ListView2.EndUpdate() End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) _ Handles Button2.Click ExtractIcon_2() End Sub
You may have noticed that there are many similarities between the first ExtractIcon sub (ExtractIcon_1) and ExtractIcon_2. It is basically verbatim the same, except for the assignment of the icon. ExtractIcon_2 calls the GetIcons_2 method, which returns the specified icon with the specified size and settings. Lastly, add the following code to see another Windows API method to extract icons:
<DllImport("shell32.dll", CharSet:=CharSet.Auto)> Shared Function ExtractIconEx(ByVal szFileName As String, ByVal nIconIndex As Integer, ByVal phiconLarge() As IntPtr, ByVal phiconSmall() As IntPtr, ByVal nIcons As Integer) As Integer End Function <DllImport("user32.dll", EntryPoint:="DestroyIcon", _ SetLastError:=True)> Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Integer End Function Private Const MAX_PATH As Integer = 260 Private Const MAX_TYPE As Integer = 80 Public Function GetIcons_3(ByVal strPath As String, _ ByVal blnLarge As Boolean) As Icon Dim intCount As Integer = 0 Dim iptLarge As IntPtr() = New IntPtr(0) {IntPtr.Zero} Dim iptSmall As IntPtr() = New IntPtr(0) {IntPtr.Zero} Try If (blnLarge) Then intCount = ExtractIconEx(strPath, 0, iptSmall, _ iptLarge, 1) Else intCount = ExtractIconEx(strPath, 0, iptLarge, _ iptSmall, 1) End If If (intCount > 0 AndAlso Not iptSmall(0).Equals _ (IntPtr.Zero)) Then Dim extractedIcon As Icon = Icon.FromHandle _ (iptSmall(0)).Clone() Return extractedIcon Else Return Nothing End If Catch ex As Exception Throw New ApplicationException("Error: ", ex) Finally For Each ptr As IntPtr In iptSmall If (Not ptr.Equals(IntPtr.Zero)) Then DestroyIcon(ptr) End If Next ptr For Each ptr As IntPtr In iptLarge If Not (ptr.Equals(IntPtr.Zero)) Then DestroyIcon(ptr) End If Next ptr End Try End Function
The ExtractIconEx function creates an array of handles to icons extracted from the specified file.
Additional Reading
I wrote the following articles some time ago. They should give you more detail on understanding File Associations.
The code for this article is available on GitHub.
Conclusion
Complicated things are sometimes not too complicated. Extracting icons from files will come in handy, and it polishes off your program’s little features nicely.