Imports System.IO
Imports System.Runtime.InteropServices
Public Class Form1

    Private FileNames As New List(Of FileInfo)
    Private Cache As New Dictionary(Of Integer, ListViewItem)

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ListView1.View = View.LargeIcon
        ListView1.LargeImageList = ImageList1
        ListView1.VirtualMode = True
        ListView1.VirtualListSize = 0

        ImageList1.ImageSize = New Size(100, 100)
        ImageList1.ColorDepth = ColorDepth.Depth32Bit
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Using folder As New FolderBrowserDialog
            If folder.ShowDialog = Windows.Forms.DialogResult.OK Then
                Cache.Clear()
                ListView1.Items.Clear()
                ImageList1.Images.Clear()

                Dim di As New DirectoryInfo(folder.SelectedPath)
                FileNames.Clear()
                For Each fi As FileInfo In di.GetFiles
                    Select Case fi.Extension.ToUpper
                        Case ".BMP", ".JPG", ".PNG", ".GIF"
                            FileNames.Add(fi)
                    End Select
                Next

                ListView1.VirtualListSize = FileNames.Count
                ListView1.Refresh()
            End If
        End Using
    End Sub

    Private Sub listView1_RetrieveVirtualItem(ByVal sender As Object, ByVal e As RetrieveVirtualItemEventArgs) Handles ListView1.RetrieveVirtualItem
        If Cache.ContainsKey(e.ItemIndex) Then
            e.Item = Cache(e.ItemIndex)
        ElseIf e.ItemIndex < FileNames.Count Then
            Dim FullFileName As String = FileNames(e.ItemIndex).FullName
            ImageList1.Images.Add(Shell.GetThumbnailImage(FullFileName, 100, 32))
            Dim LVI As New ListViewItem(FileNames(e.ItemIndex).Name, ImageList1.Images.Count - 1)
            Cache.Add(e.ItemIndex, LVI)
            e.Item = LVI
        End If
    End Sub

End Class

Public Class Shell

    Public Shared Function GetThumbnailImage(ByVal fileName As String, _
  ByVal longestEdge As Integer, ByVal colorDepth As Integer) As Image

        Dim desktopFolder As IShellFolder = Nothing
        Dim someFolder As IShellFolder = Nothing
        Dim extract As IExtractImage = Nothing
        Dim pidl As IntPtr
        Dim filePidl As IntPtr

        Const MAX_PATH As Integer = 260

        'Manually define the IIDs for IShellFolder and IExtractImage
        Dim IID_IShellFolder = New Guid("000214E6-0000-0000-C000-000000000046")
        Dim IID_IExtractImage = New Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")

        'Divide the file name into a path and file name
        Dim folderName = Path.GetDirectoryName(fileName)
        Dim shortFileName = Path.GetFileName(fileName)

        'Get the desktop IShellFolder
        ShellInterop.SHGetDesktopFolder(desktopFolder)

        'Get the parent folder IShellFolder
        desktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, 0, pidl, 0)
        desktopFolder.BindToObject(pidl, IntPtr.Zero, IID_IShellFolder, someFolder)

        'Get the file's IExtractImage
        someFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, shortFileName, 0, filePidl, 0)
        someFolder.GetUIObjectOf(IntPtr.Zero, 1, filePidl, IID_IExtractImage, 0, extract)

        'Set the size
        Dim size As SIZE_API_STRUCTURE
        size.cx = 500
        size.cy = 500

        Dim flags = IEIFLAG.ORIGSIZE ' Or IEIFLAG.QUALITY
        Dim bmp As IntPtr
        Dim thePath = Marshal.AllocHGlobal(MAX_PATH)

        'Interop will throw an exception if one of these calls fail.
        Try
            extract.GetLocation(thePath, MAX_PATH, 0, size, colorDepth, flags)
            extract.Extract(bmp)
        Catch ex As Exception
        End Try


        'Free the global memory we allocated for the path string
        Marshal.FreeHGlobal(thePath)

        'Free the pidls. The Runtime Callable Wrappers 
        'should automatically release the COM objects
        Marshal.FreeCoTaskMem(pidl)
        Marshal.FreeCoTaskMem(filePidl)

        If Not bmp.Equals(IntPtr.Zero) Then
            GetThumbnailImage = Image.FromHbitmap(bmp)
        Else
            GetThumbnailImage = Nothing
        End If
    End Function

End Class

Public Enum IEIFLAG As Integer
    ASYNC = &H1
    CACHE = &H2
    ASPECT = &H4
    OFFLINE = &H8
    GLEAM = &H10
    SCREEN = &H20
    ORIGSIZE = &H40
    NOSTAMP = &H80
    NOBORDER = &H100
    QUALITY = &H200
End Enum

<StructLayout(LayoutKind.Sequential)> _
Public Structure STRRET_CSTR
    Public uType As Integer
    <FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)> _
    Public pOleStr As String
    <FieldOffset(4)> _
    Public uOffset As Integer
    <FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst:=520)> _
    Public strName As Byte()
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure SIZE_API_STRUCTURE
    Public cx As Integer
    Public cy As Integer
End Structure

<ComImportAttribute(), _
 GuidAttribute("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1"), _
 InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IExtractImage

    Sub GetLocation( _
        ByVal pszPathBuffer As IntPtr, _
        ByVal cch As Integer, _
        ByRef pdwPriority As Integer, _
        ByRef prgSize As SIZE_API_STRUCTURE, _
        ByVal dwRecClrDepth As Integer, _
        ByRef pdwFlags As Integer)

    Sub Extract(ByRef phBmpThumbnail As IntPtr)

End Interface

<ComImportAttribute(), _
GuidAttribute("000214E6-0000-0000-C000-000000000046"), _
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IShellFolder

    Sub ParseDisplayName( _
      ByVal hWnd As IntPtr, _
      ByVal pbc As IntPtr, _
      ByVal pszDisplayName As String, _
      ByRef pchEaten As Integer, _
      ByRef ppidl As System.IntPtr, _
      ByRef pdwAttributes As Integer)

    Sub EnumObjects( _
      ByVal hwndOwner As IntPtr, _
      <MarshalAs(UnmanagedType.U4)> ByVal grfFlags As Integer, _
      <Out()> ByRef ppenumIDList As IntPtr)

    Sub BindToObject( _
      ByVal pidl As IntPtr, _
      ByVal pbcReserved As IntPtr, _
      ByRef riid As Guid, _
      ByRef ppvOut As IShellFolder)

    Sub BindToStorage( _
      ByVal pidl As IntPtr, _
      ByVal pbcReserved As IntPtr, _
      ByRef riid As Guid, _
      <Out()> ByVal ppvObj As IntPtr)

    <PreserveSig()> _
    Function CompareIDs( _
    ByVal lParam As IntPtr, _
    ByVal pidl1 As IntPtr, _
    ByVal pidl2 As IntPtr) As Integer

    Sub CreateViewObject( _
      ByVal hwndOwner As IntPtr, _
      ByRef riid As Guid, _
      ByVal ppvOut As Object)

    Sub GetAttributesOf( _
      ByVal cidl As Integer, _
      ByVal apidl As IntPtr, _
      <MarshalAs(UnmanagedType.U4)> ByRef rgfInOut As Integer)

    Sub GetUIObjectOf( _
      ByVal hwndOwner As IntPtr, _
      ByVal cidl As Integer, _
      ByRef apidl As IntPtr, _
      ByRef riid As Guid, _
      <Out()> ByVal prgfInOut As Integer, _
      <Out(), MarshalAs(UnmanagedType.IUnknown)> ByRef ppvOut As Object)

    Sub GetDisplayNameOf( _
      ByVal pidl As IntPtr, _
      <MarshalAs(UnmanagedType.U4)> ByVal uFlags As Integer, _
      ByRef lpName As STRRET_CSTR)

    Sub SetNameOf( _
      ByVal hwndOwner As IntPtr, _
      ByVal pidl As IntPtr, _
      <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszName As String, _
      <MarshalAs(UnmanagedType.U4)> ByVal uFlags As Integer, _
      ByRef ppidlOut As IntPtr)

End Interface

Public Class ShellInterop
    <DllImport("shell32.dll", CharSet:=CharSet.Auto)> _
    Public Shared Function SHGetDesktopFolder( _
    <Out()> ByRef ppshf As IShellFolder) As Integer
    End Function
End Class