C# get thumbnail from file via windows api
Ran across this today -- it's a few months old, but it got the job done for me (on Win7, extracting thumbnails on MPEG-4 files):
- Source : https://github.com/dbarros/WindowsAPICodePack
- Nuget : https://www.nuget.org/packages/WindowsAPICodePack-Shell
Code:
ShellFile shellFile = ShellFile.FromFilePath(pathToYourFile);
Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
Hope it helps!
Extract thumbnail for any file in Windows
Some time ago I wrote a ThumbnailProvider that loads a thumbnail from the Win API. Supports transparent images. This is the implementation:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;
namespace ThumbnailGenerator
{
[Flags]
public enum ThumbnailOptions
{
None = 0x00,
BiggerSizeOk = 0x01,
InMemoryOnly = 0x02,
IconOnly = 0x04,
ThumbnailOnly = 0x08,
InCacheOnly = 0x10,
}
public class WindowsThumbnailProvider
{
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string path,
// The following parameter is not used - binding context.
IntPtr pbc,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteObject(IntPtr hObject);
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
internal 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);
};
internal enum SIGDN : uint
{
NORMALDISPLAY = 0,
PARENTRELATIVEPARSING = 0x80018001,
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
DESKTOPABSOLUTEPARSING = 0x80028000,
PARENTRELATIVEEDITING = 0x80031001,
DESKTOPABSOLUTEEDITING = 0x8004c000,
FILESYSPATH = 0x80058000,
URL = 0x80068000
}
internal enum HResult
{
Ok = 0x0000,
False = 0x0001,
InvalidArguments = unchecked((int)0x80070057),
OutOfMemory = unchecked((int)0x8007000E),
NoInterface = unchecked((int)0x80004002),
Fail = unchecked((int)0x80004005),
ElementNotFound = unchecked((int)0x80070490),
TypeElementNotFound = unchecked((int)0x8002802B),
NoObject = unchecked((int)0x800401E5),
Win32ErrorCanceled = 1223,
Canceled = unchecked((int)0x800704C7),
ResourceInUse = unchecked((int)0x800700AA),
AccessDenied = unchecked((int)0x80030005)
}
[ComImportAttribute()]
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemImageFactory
{
[PreserveSig]
HResult GetImage(
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size,
[In] ThumbnailOptions flags,
[Out] out IntPtr phbm);
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeSize
{
private int width;
private int height;
public int Width { set { width = value; } }
public int Height { set { height = value; } }
};
[StructLayout(LayoutKind.Sequential)]
public struct RGBQUAD
{
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}
public static Bitmap GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
{
IntPtr hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
try
{
// return a System.Drawing.Bitmap from the hBitmap
return GetBitmapFromHBitmap(hBitmap);
}
finally
{
// delete HBitmap to avoid memory leaks
DeleteObject(hBitmap);
}
}
public static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
{
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap);
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32)
return bmp;
return CreateAlphaBitmap(bmp, PixelFormat.Format32bppArgb);
}
public static Bitmap CreateAlphaBitmap(Bitmap srcBitmap, PixelFormat targetPixelFormat)
{
Bitmap result = new Bitmap(srcBitmap.Width, srcBitmap.Height, targetPixelFormat);
Rectangle bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
BitmapData srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);
bool isAlplaBitmap = false;
try
{
for (int y = 0; y <= srcData.Height - 1; y++)
{
for (int x = 0; x <= srcData.Width - 1; x++)
{
Color pixelColor = Color.FromArgb(
Marshal.ReadInt32(srcData.Scan0, (srcData.Stride * y) + (4 * x)));
if (pixelColor.A > 0 & pixelColor.A < 255)
{
isAlplaBitmap = true;
}
result.SetPixel(x, y, pixelColor);
}
}
}
finally
{
srcBitmap.UnlockBits(srcData);
}
if (isAlplaBitmap)
{
return result;
}
else
{
return srcBitmap;
}
}
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
{
IShellItem nativeShellItem;
Guid shellItem2Guid = new Guid(IShellItem2Guid);
int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem);
if (retCode != 0)
throw Marshal.GetExceptionForHR(retCode);
NativeSize nativeSize = new NativeSize();
nativeSize.Width = width;
nativeSize.Height = height;
IntPtr hBitmap;
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap);
Marshal.ReleaseComObject(nativeShellItem);
if (hr == HResult.Ok) return hBitmap;
throw Marshal.GetExceptionForHR((int)hr);
}
}
}
Then you can use it in the following way:
int THUMB_SIZE = 256;
Bitmap thumbnail = WindowsThumbnailProvider.GetThumbnail(
fileName, THUMB_SIZE, THUMB_SIZE, ThumbnailOptions.None);
Remember that you need to Dispose() the bitmap after using it.
How to get thumbnails from a file
There are different types of thumbnails that can be retrieved from Windows.
- Picture
- Song Album Art
- Document Icon
- Folder
- File Group
- Single Item
Microsoft has a nice sample project called FileThumbnails that lets you play with each type. This project was updated for Windows10 and VS 2019 in March 2020. Although it's a universal windows project instead of winforms.
After playing with the different modes I found the one you are after for Solid Edge files is #6.
internal class FileExtensions
{
public static readonly string[] SEfiles = new string[] { ".dft", ".par", ".asm" };
}
FileOpenPicker openPicker = new FileOpenPicker();
foreach (string extension in FileExtensions.SEfiles)
{
openPicker.FileTypeFilter.Add(extension);
}
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
const ThumbnailMode thumbnailMode = ThumbnailMode.SingleItem;
bool fastThumbnail = FastThumbnailCheckBox.IsChecked.Value;
ThumbnailOptions thumbnailOptions = ThumbnailOptions.UseCurrentScale;
if (fastThumbnail)
{
thumbnailOptions |= ThumbnailOptions.ReturnOnlyIfCached;
}
using (StorageItemThumbnail thumbnail = await file.GetScaledImageAsThumbnailAsync(thumbnailMode, size, thumbnailOptions))
{
if (thumbnail != null)
{
MainPage.DisplayResult(ThumbnailImage, OutputTextBlock, thumbnailMode.ToString(), size, file, thumbnail, false);
}
else
{
rootPage.NotifyUser(Errors.NoThumbnail, NotifyType.StatusMessage);
}
}
}
public static void DisplayResult(Image image, TextBlock textBlock, string thumbnailModeName, uint size, IStorageItem item, StorageItemThumbnail thumbnail, bool isGroup)
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(thumbnail);
image.Source = bitmapImage;
textBlock.Text = String.Format("ThumbnailMode.{0}\n"
+ "{1} used: {2}\n"
+ "Requested size: {3}\n"
+ "Returned size: {4}x{5}",
thumbnailModeName,
isGroup ? "Group" : item.IsOfType(StorageItemTypes.File) ? "File" : "Folder",
item.Name,
size,
thumbnail.OriginalWidth,
thumbnail.OriginalHeight);
}
Result Example:
Get thumbnail of Network DWG file by Windows API Code Pack
There must be something wrong happening on your side because the following code works here:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Shell;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string fileName = @"\\PC\Users\Public\bitmap.bmp";
ShellFile shellFile = ShellFile.FromFilePath(fileName);
ShellThumbnail thumbnail = shellFile.Thumbnail;
var pictureBox = new PictureBox
{
Image = thumbnail.Bitmap,
Dock = DockStyle.Fill
};
Controls.Add(pictureBox);
}
}
}
Check the following:
- try with another extension to see if it affects all of them or not
- try to re-register thumbnails handlers, just a guess but SageThumbs might fix this by registering it and unregistering it as the default handler for extensions
- if that matters, I've used the Code Pack I've myself pushed to NuGet : https://www.nuget.org/packages/WindowsAPICodePack-Shell/ (not sure that might be the issue since I haven't changed anything)
VB.NET get any file thumbnail in picturebox as an image image programmatically
Try the following which is adapted from C# get thumbnail from file via windows api
Download/install NuGet package Microsoft-WindowsAPICodePack-Shell
Imports Microsoft.WindowsAPICodePack.Shell
Imports System.IO
...
Private Function GetThumbnailBytes(filename As String, desiredHeight As Integer) As Byte()
Dim thumbnailBytes As Byte()
Using sfile As ShellFile = ShellFile.FromFilePath(filename)
Dim thumbBmp As Bitmap = sfile.Thumbnail.ExtraLargeBitmap
'compute new width
Dim Ratio As Double = CDbl(thumbBmp.Width / thumbBmp.Height)
Dim height As Integer = desiredHeight
Dim width As Integer = CInt(height / Ratio)
'resize
Using resizedBmp As Bitmap = New Bitmap(thumbBmp, width, height)
Using ms As MemoryStream = New MemoryStream()
resizedBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
thumbnailBytes = ms.ToArray()
End Using
End Using
End Using
Return thumbnailBytes
End Function
Private Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
Using ofd As OpenFileDialog = New OpenFileDialog()
If ofd.ShowDialog() = DialogResult.OK Then
Dim thumbnailBytes = GetThumbnailBytes(ofd.FileName, 60)
Dim thumbnail = GetThumbnail(ofd.FileName, 60)
Using ms As MemoryStream = New MemoryStream(thumbnailBytes)
PictureBox1.Image = Image.FromStream(ms)
PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
End Using
End If
End Using
End Sub
Resources
- C# get thumbnail from file via windows api
Related Topics
C# SQL Server - Passing a List to a Stored Procedure
Determine the Number of Lines Within a Text File
What Is the Use of "Ref" for Reference-Type Variables in C#
C# Convert String from Utf-8 to Iso-8859-1 (Latin1) H
Accessing UI (Main) Thread Safely in Wpf
Reflection to Identify Extension Methods
Serializing and Deserializing Expression Trees in C#
Is Int[] a Reference Type or a Value Type
Read Xml Attribute Using Xmldocument
Deserializing JSON When Sometimes Array and Sometimes Object
How Create a New Deep Copy (Clone) of a List<T>
Is There a Generic Constructor with Parameter Constraint in C#
Solution for Overloaded Operator Constraint in .Net Generics
What's the Point of the Var Keyword
Best Way to Access a Control on Another Form in Windows Forms