none
How to get the small Icon without an arrow of a shortcut link

    Question

  • How to get the icon of a shortcut link in VB.Net, please note the icon of a shortcut is not nessecarily the icon of the item the link points to. And please note a shortcut may refer to some special location, like C:\ or My Computer

    Tried so far:

    Dim hImgSmall As IntPtr = SHGetFileInfo(filePath, 0, shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON) does a job, but returns an icon with an arrow.

    Using IShellLink works for some shortcuts (small icon of the shortcut without the arrow), but gives an empty IconLocation for of shortcuts to special locations (like disk, control panel, my computer, ect..) or shortcuts that have a custom icon.




    IShellLink




    Tuesday, March 21, 2017 1:59 PM

All replies

  • If you don't want the arrow on the icon, you can call SHGetFileInfo() with SHGFI_SYSICONINDEX flag to get the icon index from the System Imagelist.

    Then you can get the icon handle with ImageList_GetIcon()

    Tuesday, March 21, 2017 2:44 PM
  • What you want an Icon or a Shortcut, it seems to me you're mixing something.

    Success
    Cor

    Tuesday, March 21, 2017 3:32 PM
  •  Here is one way to get the Small 16x16,  Large 32x32,  Extra Large 48x48,  or Jumbo 256x256 icon from a file or folder using a similar method as Castorix31 has mentioned.  Add the IconHelper class below to your project.

    Imports System.Runtime.InteropServices
    
    Public Enum IconSize As Integer
        ''' <summary>The 32x32 Icon</summary>
        Large = &H0
        ''' <summary>The 16x16 Icon</summary>
        Small = &H1
        ''' <summary>The 48x48 Icon</summary>
        ExtraLarge = &H2
        ''' <summary>The 256x256 Icon</summary>
        Jumbo = &H4
    End Enum
    
    Public Class IconHelper
        Private Const SHGFI_ICON As UInteger = &H100
        Private Const SHGFI_SYSICONINDEX As UInteger = &H4000
        Private Const ILD_TRANSPARENT As UInteger = &H1
        Private Const ILD_IMAGE As UInteger = &H20
        Private Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
    
        <DllImport("shell32.dll", EntryPoint:="#727")>
        Private Shared Function SHGetImageList(ByVal iImageList As Integer, ByRef riid As Guid, ByRef ppv As IImageList) As Integer
        End Function
    
        <DllImport("shell32.dll", EntryPoint:="SHGetFileInfoW", CallingConvention:=CallingConvention.StdCall)>
        Private Shared Function SHGetFileInfoW(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String, ByVal dwFileAttributes As UInteger, ByRef psfi As SHFILEINFOW, ByVal cbFileInfo As Integer, ByVal uFlags As UInteger) As Integer
        End Function
    
        <DllImport("user32.dll", EntryPoint:="DestroyIcon")>
        Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
    
        <StructLayout(LayoutKind.Sequential)>
        Public Structure RECT
            Public left, top, right, bottom As Integer
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.[Unicode])>
        Private Structure SHFILEINFOW
            Public hIcon As IntPtr
            Public iIcon As Integer
            Public dwAttributes As UInteger
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public szDisplayName As String
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> Public szTypeName As String
        End Structure
    
        <StructLayout(LayoutKind.Sequential)>
        Private Structure IMAGELISTDRAWPARAMS
            Public cbSize As Integer
            Public himl As IntPtr
            Public i As Integer
            Public hdcDst As IntPtr
            Public x As Integer
            Public y As Integer
            Public cx As Integer
            Public cy As Integer
            Public xBitmap As Integer
            Public yBitmap As Integer
            Public rgbBk As Integer
            Public rgbFg As Integer
            Public fStyle As Integer
            Public dwRop As Integer
            Public fState As Integer
            Public Frame As Integer
            Public crEffect As Integer
        End Structure
    
        <StructLayout(LayoutKind.Sequential)>
        Private Structure IMAGEINFO
            Public hbmImage As IntPtr
            Public hbmMask As IntPtr
            Public Unused1 As Integer
            Public Unused2 As Integer
            Public rcImage As RECT
        End Structure
    
        <ComImport(), Guid("46EB5926-582E-4017-9FDF-E8998DAA0950"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Private Interface IImageList
            <PreserveSig()> Function Add(ByVal hbmImage As IntPtr, ByVal hbmMask As IntPtr, ByRef pi As Integer) As Integer
            <PreserveSig()> Function ReplaceIcon(ByVal i As Integer, ByVal hicon As IntPtr, ByRef pi As Integer) As Integer
            <PreserveSig()> Function SetOverlayImage(ByVal iImage As Integer, ByVal iOverlay As Integer) As Integer
            <PreserveSig()> Function Replace(ByVal i As Integer, ByVal hbmImage As IntPtr, ByVal hbmMask As IntPtr) As Integer
            <PreserveSig()> Function AddMasked(ByVal hbmImage As IntPtr, ByVal crMask As Integer, ByRef pi As Integer) As Integer
            <PreserveSig()> Function Draw(ByRef pimldp As IMAGELISTDRAWPARAMS) As Integer
            <PreserveSig()> Function Remove(ByVal i As Integer) As Integer
            <PreserveSig()> Function GetIcon(ByVal i As Integer, ByVal flags As Integer, ByRef picon As IntPtr) As Integer
            <PreserveSig()> Function GetImageInfo(ByVal i As Integer, ByRef pImageInfo As IMAGEINFO) As Integer
            <PreserveSig()> Function Copy(ByVal iDst As Integer, ByVal punkSrc As IImageList, ByVal iSrc As Integer, ByVal uFlags As Integer) As Integer
            <PreserveSig()> Function Merge(ByVal i1 As Integer, ByVal punk2 As IImageList, ByVal i2 As Integer, ByVal dx As Integer, ByVal dy As Integer, ByRef riid As Guid, ByRef ppv As IntPtr) As Integer
            <PreserveSig()> Function Clone(ByRef riid As Guid, ByRef ppv As IntPtr) As Integer
            <PreserveSig()> Function GetImageRect(ByVal i As Integer, ByRef prc As RECT) As Integer
            <PreserveSig()> Function GetIconSize(ByRef cx As Integer, ByRef cy As Integer) As Integer
            <PreserveSig()> Function SetIconSize(ByVal cx As Integer, ByVal cy As Integer) As Integer
            <PreserveSig()> Function GetImageCount(ByRef pi As Integer) As Integer
            <PreserveSig()> Function SetImageCount(ByVal uNewCount As Integer) As Integer
            <PreserveSig()> Function SetBkColor(ByVal clrBk As Integer, ByRef pclr As Integer) As Integer
            <PreserveSig()> Function GetBkColor(ByRef pclr As Integer) As Integer
            <PreserveSig()> Function BeginDrag(ByVal iTrack As Integer, ByVal dxHotspot As Integer, ByVal dyHotspot As Integer) As Integer
            <PreserveSig()> Function EndDrag() As Integer
            <PreserveSig()> Function DragEnter(ByVal hwndLock As IntPtr, ByVal x As Integer, ByVal y As Integer) As Integer
            <PreserveSig()> Function DragLeave(ByVal hwndLock As IntPtr) As Integer
            <PreserveSig()> Function DragMove(ByVal x As Integer, ByVal y As Integer) As Integer
            <PreserveSig()> Function SetDragCursorImage(ByRef punk As IImageList, ByVal iDrag As Integer, ByVal dxHotspot As Integer, ByVal dyHotspot As Integer) As Integer
            <PreserveSig()> Function DragShowNolock(ByVal fShow As Integer) As Integer
            <PreserveSig()> Function GetDragImage(ByRef ppt As Point, ByRef pptHotspot As Point, ByRef riid As Guid, ByRef ppv As IntPtr) As Integer
            <PreserveSig()> Function GetItemFlags(ByVal i As Integer, ByRef dwFlags As Integer) As Integer
            <PreserveSig()> Function GetOverlayImage(ByVal iOverlay As Integer, ByRef piIndex As Integer) As Integer
        End Interface
    
        Public Shared Function GetIconFrom(ByVal PathName As String, ByVal IcoSize As IconSize) As Icon
            Dim ico As Icon = Nothing
            Dim shinfo As New SHFILEINFOW()
            Dim flags As UInteger = SHGFI_SYSICONINDEX
    
            If SHGetFileInfoW(PathName, FILE_ATTRIBUTE_NORMAL, shinfo, Marshal.SizeOf(shinfo), flags) = 0 Then
                Throw New IO.FileNotFoundException()
            End If
    
            Dim iidImageList As New Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")
            Dim iml As IImageList = Nothing
            SHGetImageList(IcoSize, iidImageList, iml)
    
            If iml IsNot Nothing Then
                Dim hIcon As IntPtr = IntPtr.Zero
                iml.GetIcon(shinfo.iIcon, ILD_IMAGE, hIcon)
                ico = CType(Icon.FromHandle(hIcon).Clone, Icon)
                DestroyIcon(hIcon)
    
                If Not ico.ToBitmap.PixelFormat = Imaging.PixelFormat.Format32bppArgb Then
                    ico.Dispose()
                    iml.GetIcon(shinfo.iIcon, ILD_TRANSPARENT, hIcon)
                    ico = CType(Icon.FromHandle(hIcon).Clone, Icon)
                    DestroyIcon(hIcon)
                End If
            End If
    
            Return ico
        End Function
    End Class
    
     

     Then in your Form class,  you can call the shared GetIconFrom function of the IconHelper class like below...

    Public Class Form1
        Private Ico As Icon = Nothing
    
        Private Sub Button_GetFileIcon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_GetFileIcon.Click
            Using ofd As New OpenFileDialog
                If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    If Ico IsNot Nothing Then Ico.Dispose()
                    Ico = IconHelper.GetIconFrom(ofd.FileName, IconSize.Small) 'you can specify the Small, Large, Extra Large, or Jumbo File icon size
                    Me.Invalidate()
                End If
            End Using
        End Sub
    
        Private Sub Button_GetFolderIcon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_GetFolderIcon.Click
            Using fb As New FolderBrowserDialog
                If fb.ShowDialog = Windows.Forms.DialogResult.OK Then
                    If Ico IsNot Nothing Then Ico.Dispose()
                    Ico = IconHelper.GetIconFrom(fb.SelectedPath, IconSize.Small) 'you can specify the Small, Large, Extra Large, or Jumbo Folder icon size
                    Me.Invalidate()
                End If
            End Using
        End Sub
    
        Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            If Ico IsNot Nothing Then
                e.Graphics.DrawIcon(Ico, 100, 100)
            End If
        End Sub
    
        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            If Ico IsNot Nothing Then Ico.Dispose()
        End Sub
    End Class


    If you say it can`t be done then i`ll try it

    • Proposed as answer by Frank L. Smith Tuesday, March 21, 2017 8:25 PM
    • Edited by IronRazerz Tuesday, March 21, 2017 9:10 PM
    Tuesday, March 21, 2017 8:19 PM
  • Btw, it can be simplified  because SHGetFileInfo() returns the System Imagelist with this flag.
    Tuesday, March 21, 2017 8:49 PM