In Vista, Explorer produces really nice thumbnails of your files. It will generate a preview for supported file types, such as images, PDFs, Word documents and others. If it's not a type that has a preview, it will show its associated icon.

I’ve been working on an experimental dock application for Vista, and I needed a way to get the icon of the files the user drags onto the dock. At first I looked at the Icon.ExtractAssociatedIcon method in System.Drawing, but it gave a 48x48 XP-style icon at best, which is unacceptable for a dock. I needed Vista’s 256x256 icons and nothing less. I began poking around the Vista APIs and found the IThumbnailCache COM interface. The only problem was that it could only retrieve a thumbnail, not an icon. Eventually I found IShellItemImageFactory which gets a thumbnail when possible and reverts to a fancy Vista icon when not.
I don’t know that much about COM, so it took me a while, but I managed to make everything fit together. The C# definition of IShellItemImageFactory looks like so:
[ComImportAttribute()]
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemImageFactory
{
void GetImage(
[In, MarshalAs(UnmanagedType.Struct)] SIZE size,
[In] SIIGBF flags,
[Out] out IntPtr phbm);
}
It seems that the IShellItem implementation used in Vista also implements IShellItemImageFactory, so to get a thumbnail, all you need to do is get an IShellItem for your desired item, cast it to IShellItemImageFactory and call GetImage. The easiest way to get an IShellItem for a given path is to use SHCreateItemFromParsingName. From there you can use the Imaging.CreateBitmapSourceFromHBitmap method in System.Windows.Interop to create a WPF BitmapSource object (for use with a WPF Image control) from the IntPtr pointing to the GDI+ bitmap returned by GetImage. Or, if you aren’t using WPF, you can use whatever other methods available in System.Drawing or elsewhere to convert your shiny new thumbnail to a more usable format.
Using the code below, you should be able to get beautiful thumbnails like these in your WPF app in no time!

The following class, ThumbnailGenerator, and supporting COM interface definitions, structs and enums were either defined by me or taken from the wonderful PInvoke.net. All the interop stuff I discovered while working on this has since been posted on PInvoke.net. The following code is from my Vista Toolbelt project, which is just my collection of useful Vista, WPF and related classes and code. Feel free to use it or modify it however you like. I haven’t tested it extensively, but there’s not much too it, so I don’t foresee any problems. Should you find something though, please let me know!
ThumbnailGenerator.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows;
using VistaToolbelt.Interop.Native;
namespace VistaToolbelt.Shell
{
/// <summary>
/// Assists in generating thumbnails for shell items.
/// </summary>
public static class ThumbnailGenerator
{
/// <summary>
/// Generates an Explorer-style thumbnail for any file or shell item. Requires Vista or above.
/// </summary>
/// <param name="filename" />The filename of the item.</param>
/// <returns>The thumbnail of the item.</returns>
public static ImageSource GenerateThumbnail(String filename)
{
IShellItem ppsi = null;
IntPtr hbitmap = IntPtr.Zero;
Guid uuid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe");
// Create an IShellItem from the filename.
UnsafeNativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, uuid, out ppsi);
// Get the thumbnail image.
((IShellItemImageFactory)ppsi).GetImage(new SIZE(256, 256), 0x0, out hbitmap);
// Convert from GDI HBITMAP to WPF BitmapSource.
BitmapSource source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hbitmap,
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
// Release COM stuff to avoid memory leaks.
Marshal.ReleaseComObject(ppsi);
Marshal.Release(hbitmap);
return source;
}
}
}
NativeInterop.cs:
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System;
namespace VistaToolbelt.Interop.Native
{
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{
this.cx = cx;
this.cy = cy;
}
}
public enum SIGDN : uint
{
NORMALDISPLAY = 0,
PARENTRELATIVEPARSING = 0x80018001,
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
DESKTOPABSOLUTEPARSING = 0x80028000,
PARENTRELATIVEEDITING = 0x80031001,
DESKTOPABSOLUTEEDITING = 0x8004c000,
FILESYSPATH = 0x80058000,
URL = 0x80068000
}
[Flags]
public enum SIIGBF
{
SIIGBF_RESIZETOFIT = 0x00,
SIIGBF_BIGGERSIZEOK = 0x01,
SIIGBF_MEMORYONLY = 0x02,
SIIGBF_ICONONLY = 0x04,
SIIGBF_THUMBNAILONLY = 0x08,
SIIGBF_INCACHEONLY = 0x10,
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)]Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)]Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
};
[ComImportAttribute()]
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemImageFactory
{
void GetImage(
[In, MarshalAs(UnmanagedType.Struct)] SIZE size,
[In] SIIGBF flags,
[Out] out IntPtr phbm);
}
[SuppressUnmanagedCodeSecurity]
public static class UnsafeNativeMethods
{
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void SHCreateItemFromParsingName(
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
[In] IntPtr pbc,
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem ppv);
}
}