I have made an application that presents you a list of files in your computer. Whenever you click any item in the list, a small PictureBox next to it should show the thumbnail of the corresponding file. I am using C# on Windows 7.
To obtain the thumbnail, I've recurred to a method posted in a different question. First, I reference the Windows API Code pack. Then, I use the following code:
ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;
This doesn't always work. Sometimes, the thumbnail shown is merely the 'default application' icon. I've found out that the real thumbnail is only shown if Windows had previously generated the thumbnail for that file and stored it in the thumbnails cache. This means that I have to manually open a folder, wait for Windows to generate thumbnails for each file, and then my application will be able to see those thumbs.
How can my program force Windows 7 to generate real thumbnails before using them?
Update (by Li0liQ)
It is possible to force thumbnail retrieval by adding FormatOption:
ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
shellFile.Thumbnail.FormatOption = ShellThumbnailFormatOption.ThumbnailOnly;
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;
however, I'm getting an exception in case thumbnail is not there yet:
The current ShellObject does not have a valid thumbnail handler or there was a problem in extracting the thumbnail for this specific shell object. ---> System.Runtime.InteropServices.COMException: Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))
See How do I refresh a file's thumbnail in Windows Explorer? question and code snippet for potential clues.
Here is a piece of code that extracts thumbnail bitmaps (using Windows Vista or higher only). It's based on the cool IShellItemImageFactory interface:
static void Main(string[] args)
{
// you can use any type of file supported by your windows installation.
string path = @"c:\temp\whatever.pdf";
using (Bitmap bmp = ExtractThumbnail(path, new Size(1024, 1024), SIIGBF.SIIGBF_RESIZETOFIT))
{
bmp.Save("whatever.png", ImageFormat.Png);
}
}
public static Bitmap ExtractThumbnail(string filePath, Size size, SIIGBF flags)
{
if (filePath == null)
throw new ArgumentNullException("filePath");
// TODO: you might want to cache the factory for different types of files
// as this simple call may trigger some heavy-load underground operations
IShellItemImageFactory factory;
int hr = SHCreateItemFromParsingName(filePath, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out factory);
if (hr != 0)
throw new Win32Exception(hr);
IntPtr bmp;
hr = factory.GetImage(size, flags, out bmp);
if (hr != 0)
throw new Win32Exception(hr);
return Bitmap.FromHbitmap(bmp);
}
[Flags]
public enum SIIGBF
{
SIIGBF_RESIZETOFIT = 0x00000000,
SIIGBF_BIGGERSIZEOK = 0x00000001,
SIIGBF_MEMORYONLY = 0x00000002,
SIIGBF_ICONONLY = 0x00000004,
SIIGBF_THUMBNAILONLY = 0x00000008,
SIIGBF_INCACHEONLY = 0x00000010,
SIIGBF_CROPTOSQUARE = 0x00000020,
SIIGBF_WIDETHUMBNAILS = 0x00000040,
SIIGBF_ICONBACKGROUND = 0x00000080,
SIIGBF_SCALEUP = 0x00000100,
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHCreateItemFromParsingName(string path, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemImageFactory factory);
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
private interface IShellItemImageFactory
{
[PreserveSig]
int GetImage(Size size, SIIGBF flags, out IntPtr phbm);
}
Additional notes:
GetImage
method has various interesting flags (SIIGBF
) you can play with. REGDB_E_CLASSNOTREG
is a typical kind of error you may get in these cases.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With