C# получить эскиз из файла через Windows API

Проводник Windows имеет возможность показывать эскизы файлов. Эти эскизы предоставляются расширениями ядра и сторонних производителей.

Я знаю, как расширить оболочку для предоставления эскизов в Windows.

То, что я хочу сделать, это получить эскиз изображения из любого файла в системе через оболочку с использованием C#. Это возможно?

По сути, я пишу собственный файловый браузер и хочу показывать миниатюры, и не могу разобрать каждый файл на планете, чтобы создать свои собственные миниатюры.

Пояснение: многие ответы, кажется, сосредоточены вокруг миниатюр веб-страницы или масштабирования изображения. Но это совсем не то, что я ищу. Я хочу попросить у Windows миниатюрное представление этих типов файлов: .DOC, .PDF, .3DM, .DWG... и еще около десятка. Я не хочу разбирать, отображать и создавать эскизы самостоятельно, потому что Windows уже знает, как это сделать.

Код, который я разместил как ответ, на самом деле работает... может быть, его можно немного упростить и очистить.

7 ответов

Решение

Сегодня я столкнулся с этим - ему несколько месяцев, но он выполнил свою работу за меня (на Win7, извлечение эскизов из файлов MPEG-4):

Код:

ShellFile shellFile = ShellFile.FromFilePath(pathToYourFile);
Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;

Надеюсь, поможет!

Миниатюры Microsoft Office в SharePoint по адресу http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx. это именно то, что вы хотите. (У меня не было проблем с преобразованием кода VB.NET в C# с использованием http://www.developerfusion.com/tools/convert/vb-to-csharp/.)

Что касается кода, который вы разместили в своем ответе, извлечение миниатюр с помощью оболочки по адресу http://www.vbaccelerator.com/home/net/code/libraries/Shell_Projects/Thumbnail_Extraction/article.asp - это оригинальная статья, из которой взят код. Я верю почти всем IExtractImage Примеры (вы находите поиск) основаны на коде этой статьи, из-за соглашения об именовании, комментариев и т. д., которые взяты из оригинала. Поскольку эта статья датируется апрелем 2003 года, в ней содержатся некоторые нестандартные (не.NET) соглашения о кодировании. Я провел некоторое базовое тестирование, и есть проблемы со сборкой мусора, освобождение неуправляемых ресурсов и другие проблемы очистки. Поэтому я настоятельно рекомендую избегать кода в этой статье. Более того, структурированный код является таким способом усложнить обслуживание.

Существует чистая более простая версия MSDN от июля 2005 года, которая называется " Миниатюры Microsoft Office в SharePoint" по адресу http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx. Этот код и код статьи имеют сходство, что позволяет мне полагать, что статья " Извлечение миниатюр с помощью оболочки" является основой для статьи SharePoint. Версия VB.NET GetThumbnailImage игнорирует longestEdge параметр, но версия C++ использует его и документирует использование ORIGSIZE а также QUALITY флаги. Кроме того, код иллюстрирует, как использовать.NET FreeCoTaskMem вместо снарядов IMalloc а также SHGetMalloc,

IExtractImage работает с файлами, папками и другими объектами пространства имен. Код MSDN работает со скрытыми файлами, тогда как код vbAccelerator требует SHCONTF_INCLUDEHIDDEN добавлен в EnumObjects вызов. Кроме того, vbAccelerator перечисляет объекты папки оболочки в поисках указанного файла, что кажется пустой тратой времени. Это могло понадобиться для поиска правильного "относительного" PIDL, который используется для GetUIObjectOf вызов.


ShellThumbnail (работа в процессе)

Завершите пример проекта по адресу http://cid-7178d2c79ba0a7e3.office.live.com/self.aspx/.Public/ShellThumbnail.zip.

Imports System.Runtime.InteropServices

Namespace Shell

    ''' <summary>
    ''' Generates a thumbnail of a folder's picture or a file's image.
    ''' </summary>
    ''' <remarks>This is the "Folder's Picture" and not the "Folder's Icon"! Use SHGetFileInfo to generate the thumbnail for a folder's icon or for a file that does not have a thumbnail handler.</remarks>
    ''' <reference>Microsoft Office Thumbnails in SharePoint at http://msdn.microsoft.com/en-us/library/aa289172%28VS.71%29.aspx.</reference>
    Public Class ShellThumbnail

        'TODO - Work out the details for image size and IEIFLAG handling.

#Region " Determining Thumbnail Size and Quality [documentation] "

        'http://support.microsoft.com/kb/835823
        'Determining Thumbnail Size and Quality
        'Browse to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer. Create or modify two DWORDs called ThumbnailSize and ThumbnailQuality. For ThumbnailSize set the value in pixels, with the default being 96. For ThumbnailQuality set the value as a number that represents the percentage quality between 50 and 100.


        'http://www.pctools.com/guides/registry/detail/1066/ (modified)
        '  User Key: [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
        'System Key: [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer]
        'Value Name: ThumbnailSize, ThumbnailQuality
        ' Data Type: REG_DWORD (DWORD Value)
        'Value Data: Size in pixels (32-255), Quality Percentage (50-100)


        'Microsoft® Windows® XP Registry Guide 
        'Jerry Honeycutt 
        '09/11/2002 
        'Microsoft Press
        'http://www.microsoft.com/mspress/books/sampchap/6232.aspx#118
        '<H3><I><A name=118></A>Thumbnails</I></H3>The Thumbnails category controls the 
        'quality of thumbnails in Windows Explorer. Table 5-10 describes the values for 
        'Image Quality and Size. Create values that you don't see in the registry. The 
        'default value for <CODE>ThumbnailQuality</CODE> is <CODE>0x5A</CODE>. The 
        'default value for <CODE>ThumbnailSize</CODE> is <CODE>0x60</CODE>. Keep in mind 
        'that higher quality and larger thumbnails require more disk space, which is not 
        'usually a problem, but they also take longer to display. Changing the quality 
        'does not affect thumbnails that already exist on the file system.
        '<P><B>Table 5-10 </B><I>Values in Thumbnails</I>
        '<P>
        '<TABLE border=0 cellSpacing=1 cellPadding=4 width="100%">
        '<TBODY>
        '<TR>
        '<TD bgColor=#999999 vAlign=top><B>Setting</B></TD>
        '<TD bgColor=#999999 vAlign=top><B>Name</B></TD>
        '<TD bgColor=#999999 vAlign=top><B>Type</B></TD>
        '<TD bgColor=#999999 vAlign=top><B>Data</B></TD></TR>
        '<TR>
        '<TD bgColor=#cccccc 
        'vAlign=top><CODE><B>HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer</B></CODE></TD>
        '<TD bgColor=#cccccc vAlign=top> </TD>
        '<TD bgColor=#cccccc vAlign=top> </TD>
        '<TD bgColor=#cccccc vAlign=top> </TD></TR>
        '<TR>
        '<TD bgColor=#cccccc vAlign=top><CODE>Image Quality</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>ThumbnailQuality</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>REG_DWORD</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>0x32 - 0x64</CODE></TD></TR>
        '<TR>
        '<TD bgColor=#cccccc vAlign=top><CODE>Size (pixels)</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>ThumbnailSize</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>REG_DWORD</CODE></TD>
        '<TD bgColor=#cccccc vAlign=top><CODE>0x20 - 0xFF</CODE></TD></TR></TBODY></TABLE></P>

#End Region

        Public Shared ReadOnly DefaultThumbnailSize As New System.Drawing.Size(96, 96)

        Public Const DefaultColorDepth As Integer = 32

        ''' <summary>
        ''' Used to request an image from an object, such as an item in a Shell folder.
        ''' </summary>
        ''' <param name="path">An absolute path to a file or folder.</param>
        Public Shared Function ExtractImage(ByVal path As String) As Bitmap
            Return ExtractImage(path, System.Drawing.Size.Empty, DefaultColorDepth, 0)
        End Function

        ''' <summary>
        ''' Used to request an image from an object, such as an item in a Shell folder.
        ''' </summary>
        ''' <param name="path">An absolute path to a file or folder.</param>
        ''' <param name="size"></param>
        Public Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size) As Bitmap
            Return ExtractImage(path, size, DefaultColorDepth, 0)
        End Function

        ''' <summary>
        ''' Used to request an image from an object, such as an item in a Shell folder.
        ''' </summary>
        ''' <param name="path">An absolute path to a file or folder.</param>
        ''' <param name="size"></param>
        ''' <param name="recommendedColorDepth">The recommended color depth in units of bits per pixel. The default is 32.</param>
        Public Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size, ByVal recommendedColorDepth As Integer) As Bitmap
            Return ExtractImage(path, size, recommendedColorDepth, 0)
        End Function

        ''' <summary>
        ''' Used to request an image from an object, such as an item in a Shell folder.
        ''' </summary>
        ''' <param name="path">An absolute path to a file or folder.</param>
        ''' <param name="size"></param>
        ''' <param name="recommendedColorDepth">The recommended color depth in units of bits per pixel. The default is 32.</param>
        Private Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size, ByVal recommendedColorDepth As Integer, ByVal flags As IEIFLAG) As Bitmap
            Dim oResult As Bitmap = Nothing

            Dim oDesktopFolder As IShellFolder = Nothing
            Dim hParentIDL As IntPtr
            Dim hIDL As IntPtr

            Dim oParentFolder As IShellFolder
            Dim hParentFolder As IntPtr
            Dim oExtractImage As IExtractImage
            Dim hExtractImage As IntPtr

            'Divide the file name into a path and file/folder name.
            Dim sFolderName As String = System.IO.Path.GetDirectoryName(path)
            Dim sBaseName As String = System.IO.Path.GetFileName(path)

            'Get the desktop IShellFolder.
            If SHGetDesktopFolder(oDesktopFolder) <> Missico.Win32.S_OK Then
                Throw New System.Runtime.InteropServices.COMException
            End If

            'Get the parent folder for the specified path.
            oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, sFolderName, 0, hParentIDL, 0)
            oDesktopFolder.BindToObject(hParentIDL, IntPtr.Zero, ShellGUIDs.IID_IShellFolder, hParentFolder)
            oParentFolder = CType(Marshal.GetTypedObjectForIUnknown(hParentFolder, GetType(IShellFolder)), IShellFolder)

            'Get the file/folder's IExtractImage
            oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, sBaseName, 0, hIDL, 0)
            oParentFolder.GetUIObjectOf(IntPtr.Zero, 1, New IntPtr() {hIDL}, ShellGUIDs.IID_IExtractImage, IntPtr.Zero, hExtractImage)

            'Free the pidls. The Runtime Callable Wrappers (RCW) should automatically release the COM objects.
            Marshal.FreeCoTaskMem(hParentIDL)
            Marshal.FreeCoTaskMem(hIDL)

            Marshal.FinalReleaseComObject(oParentFolder)
            Marshal.FinalReleaseComObject(oDesktopFolder)

            If hExtractImage = IntPtr.Zero Then

                'There is no handler for this file, which is odd. I believe we should default the file's type icon.
                Debug.WriteLine(String.Format("There is no thumbnail for the specified file '{0}'.", path), "ShellThumbnail.ExtractImage")

            Else

                oExtractImage = CType(Marshal.GetTypedObjectForIUnknown(hExtractImage, GetType(IExtractImage)), IExtractImage)

                'Set the size and flags
                Dim oSize As Missico.Win32.SIZE 'must specify a size
                Dim iFlags As IEIFLAG = flags Or IEIFLAG.IEIFLAG_ORIGSIZE Or IEIFLAG.IEIFLAG_QUALITY Or IEIFLAG.IEIFLAG_ASPECT

                If size.IsEmpty Then

                    oSize.cx = DefaultThumbnailSize.Width
                    oSize.cy = DefaultThumbnailSize.Height

                Else

                    oSize.cx = size.Width
                    oSize.cy = size.Height

                End If


                Dim hBitmap As IntPtr
                Dim sPath As New System.Text.StringBuilder(Missico.Win32.MAX_PATH, Missico.Win32.MAX_PATH)


                oExtractImage.GetLocation(sPath, sPath.Capacity, 0, oSize, recommendedColorDepth, iFlags)

                'if the specified path is to a folder then IExtractImage.Extract fails.

                Try

                    oExtractImage.Extract(hBitmap)

                Catch ex As System.Runtime.InteropServices.COMException

                    'clear the handle since extract failed
                    hBitmap = IntPtr.Zero

                    Debug.WriteLine(String.Format("There is no thumbnail for the specified folder '{0}'.", path), "ShellThumbnail.ExtractImage")

                Finally

                    Marshal.FinalReleaseComObject(oExtractImage)

                End Try

                If Not hBitmap.Equals(IntPtr.Zero) Then

                    'create the image from the handle
                    oResult = System.Drawing.Bitmap.FromHbitmap(hBitmap)

                    'dump the properties to determine what kind of bitmap is returned
                    'Missico.Diagnostics.ObjectDumper.Write(oResult)

                    'Tag={ }
                    'PhysicalDimension={Width=96, Height=96}
                    'Size={Width=96, Height=96}
                    'Width=96
                    'Height=96
                    'HorizontalResolution=96
                    'VerticalResolution=96
                    'Flags=335888
                    'RawFormat={ }
                    'PixelFormat=Format32bppRgb
                    'Palette={ }
                    'FrameDimensionsList=...
                    'PropertyIdList=...
                    'PropertyItems=...

                    Missico.Win32.DeleteObject(hBitmap) 'release the handle

                End If

            End If

            Return oResult
        End Function

    End Class

End Namespace

Это может помочь:

http://blogs.msdn.com/windowssdk/archive/2009/06/12/windows-api-code-pack-for-microsoft-net-framework.aspx

Это включает в себя API-интерфейс оболочки и позволяет вам делать почти все, что может оболочка (включая рендеринг миниатюр).

Вот класс, который я нашел в интернете. Похоже, что оригинальный код был взят с http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21789724.html, но я не вижу его, чтобы дать надлежащую атрибуцию. Я нашел источник здесь: http://www.vbforums.com/showthread.php?t=527704

Вот класс с соответствующими вызовами COM, воспроизведенный здесь для потомков:


using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace RMA.Shell
{
  public class ShellThumbnail : IDisposable
  {

    [Flags]
    private enum ESTRRET
    {
      STRRET_WSTR = 0,
      STRRET_OFFSET = 1,
      STRRET_CSTR = 2
    }

    [Flags]
    private enum ESHCONTF
    {
      SHCONTF_FOLDERS = 32,
      SHCONTF_NONFOLDERS = 64,
      SHCONTF_INCLUDEHIDDEN = 128,
    }

    [Flags]
    private enum ESHGDN
    {
      SHGDN_NORMAL = 0,
      SHGDN_INFOLDER = 1,
      SHGDN_FORADDRESSBAR = 16384,
      SHGDN_FORPARSING = 32768
    }

    [Flags]
    private enum ESFGAO
    {
      SFGAO_CANCOPY = 1,
      SFGAO_CANMOVE = 2,
      SFGAO_CANLINK = 4,
      SFGAO_CANRENAME = 16,
      SFGAO_CANDELETE = 32,
      SFGAO_HASPROPSHEET = 64,
      SFGAO_DROPTARGET = 256,
      SFGAO_CAPABILITYMASK = 375,
      SFGAO_LINK = 65536,
      SFGAO_SHARE = 131072,
      SFGAO_READONLY = 262144,
      SFGAO_GHOSTED = 524288,
      SFGAO_DISPLAYATTRMASK = 983040,
      SFGAO_FILESYSANCESTOR = 268435456,
      SFGAO_FOLDER = 536870912,
      SFGAO_FILESYSTEM = 1073741824,
      SFGAO_HASSUBFOLDER = -2147483648,
      SFGAO_CONTENTSMASK = -2147483648,
      SFGAO_VALIDATE = 16777216,
      SFGAO_REMOVABLE = 33554432,
      SFGAO_COMPRESSED = 67108864,
    }

    private enum EIEIFLAG
    {
      IEIFLAG_ASYNC = 1,
      IEIFLAG_CACHE = 2,
      IEIFLAG_ASPECT = 4,
      IEIFLAG_OFFLINE = 8,
      IEIFLAG_GLEAM = 16,
      IEIFLAG_SCREEN = 32,
      IEIFLAG_ORIGSIZE = 64,
      IEIFLAG_NOSTAMP = 128,
      IEIFLAG_NOBORDER = 256,
      IEIFLAG_QUALITY = 512
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Auto)]
    private struct STRRET_CSTR
    {
      public ESTRRET uType;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 520)]
      public byte[] cStr;
    }

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
    private struct STRRET_ANY
    {
      [FieldOffset(0)]
      public ESTRRET uType;
      [FieldOffset(4)]
      public IntPtr pOLEString;
    }
    [StructLayoutAttribute(LayoutKind.Sequential)]
    private struct SIZE
    {
      public int cx;
      public int cy;
    }

    [ComImport(), Guid("00000000-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IUnknown
    {

      [PreserveSig()]
      IntPtr QueryInterface(ref Guid riid, ref IntPtr pVoid);

      [PreserveSig()]
      IntPtr AddRef();

      [PreserveSig()]
      IntPtr Release();
    }

    [ComImportAttribute()]
    [GuidAttribute("00000002-0000-0000-C000-000000000046")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IMalloc
    {

      [PreserveSig()]
      IntPtr Alloc(int cb);

      [PreserveSig()]
      IntPtr Realloc(IntPtr pv, int cb);

      [PreserveSig()]
      void Free(IntPtr pv);

      [PreserveSig()]
      int GetSize(IntPtr pv);

      [PreserveSig()]
      int DidAlloc(IntPtr pv);

      [PreserveSig()]
      void HeapMinimize();
    }

    [ComImportAttribute()]
    [GuidAttribute("000214F2-0000-0000-C000-000000000046")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IEnumIDList
    {

      [PreserveSig()]
      int Next(int celt, ref IntPtr rgelt, ref int pceltFetched);

      void Skip(int celt);

      void Reset();

      void Clone(ref IEnumIDList ppenum);
    }

    [ComImportAttribute()]
    [GuidAttribute("000214E6-0000-0000-C000-000000000046")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IShellFolder
    {

      void ParseDisplayName(IntPtr hwndOwner, IntPtr pbcReserved,
        [MarshalAs(UnmanagedType.LPWStr)]string lpszDisplayName,
        ref int pchEaten, ref IntPtr ppidl, ref int pdwAttributes);

      void EnumObjects(IntPtr hwndOwner,
        [MarshalAs(UnmanagedType.U4)]ESHCONTF grfFlags,
        ref IEnumIDList ppenumIDList);

      void BindToObject(IntPtr pidl, IntPtr pbcReserved, ref Guid riid,
        ref IShellFolder ppvOut);

      void BindToStorage(IntPtr pidl, IntPtr pbcReserved, ref Guid riid, IntPtr ppvObj);

      [PreserveSig()]
      int CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);

      void CreateViewObject(IntPtr hwndOwner, ref Guid riid,
        IntPtr ppvOut);

      void GetAttributesOf(int cidl, IntPtr apidl,
        [MarshalAs(UnmanagedType.U4)]ref ESFGAO rgfInOut);

      void GetUIObjectOf(IntPtr hwndOwner, int cidl, ref IntPtr apidl, ref Guid riid, ref int prgfInOut, ref IUnknown ppvOut);

      void GetDisplayNameOf(IntPtr pidl,
        [MarshalAs(UnmanagedType.U4)]ESHGDN uFlags,
        ref STRRET_CSTR lpName);

      void SetNameOf(IntPtr hwndOwner, IntPtr pidl,
        [MarshalAs(UnmanagedType.LPWStr)]string lpszName,
        [MarshalAs(UnmanagedType.U4)] ESHCONTF uFlags,
        ref IntPtr ppidlOut);
    }
    [ComImportAttribute(), GuidAttribute("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IExtractImage
    {
      void GetLocation([Out(), MarshalAs(UnmanagedType.LPWStr)]
        StringBuilder pszPathBuffer, int cch, ref int pdwPriority, ref SIZE prgSize, int dwRecClrDepth, ref int pdwFlags);

      void Extract(ref IntPtr phBmpThumbnail);
    }

    private class UnmanagedMethods
    {

      [DllImport("shell32", CharSet = CharSet.Auto)]
      internal extern static int SHGetMalloc(ref IMalloc ppMalloc);

      [DllImport("shell32", CharSet = CharSet.Auto)]
      internal extern static int SHGetDesktopFolder(ref IShellFolder ppshf);

      [DllImport("shell32", CharSet = CharSet.Auto)]
      internal extern static int SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);

      [DllImport("gdi32", CharSet = CharSet.Auto)]
      internal extern static int DeleteObject(IntPtr hObject);

    }

    ~ShellThumbnail()
    {
      Dispose();
    }

    private IMalloc alloc = null;
    private bool disposed = false;
    private Size _desiredSize = new Size(100, 100);
    private Bitmap _thumbNail;

    public Bitmap ThumbNail
    {
      get
      {
        return _thumbNail;
      }
    }

    public Size DesiredSize
    {
      get { return _desiredSize; }
      set { _desiredSize = value; }
    }
    private IMalloc Allocator
    {
      get
      {
        if (!disposed)
        {
          if (alloc == null)
          {
            UnmanagedMethods.SHGetMalloc(ref alloc);
          }
        }
        else
        {
          Debug.Assert(false, "Object has been disposed.");
        }
        return alloc;
      }
    }

    public Bitmap GetThumbnail(string fileName)
    {
      if (string.IsNullOrEmpty(fileName))
        return null;

      if (!File.Exists(fileName) && !Directory.Exists(fileName))
      {
        throw new FileNotFoundException(string.Format("The file '{0}' does not exist", fileName), fileName);
      }
      if (_thumbNail != null)
      {
        _thumbNail.Dispose();
        _thumbNail = null;
      }
      IShellFolder folder = null;
      try
      {
        folder = getDesktopFolder;
      }
      catch (Exception ex)
      {
        throw ex;
      }
      if (folder != null)
      {
        IntPtr pidlMain = IntPtr.Zero;
        try
        {
          int cParsed = 0;
          int pdwAttrib = 0;
          string filePath = Path.GetDirectoryName(fileName);
          folder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, filePath, ref cParsed, ref pidlMain, ref pdwAttrib);
        }
        catch (Exception ex)
        {
          Marshal.ReleaseComObject(folder);
          throw ex;
        }
        if (pidlMain != IntPtr.Zero)
        {
          Guid iidShellFolder = new Guid("000214E6-0000-0000-C000-000000000046");
          IShellFolder item = null;
          try
          {
            folder.BindToObject(pidlMain, IntPtr.Zero, ref iidShellFolder, ref item);
          }
          catch (Exception ex)
          {
            Marshal.ReleaseComObject(folder);
            Allocator.Free(pidlMain);
            throw ex;
          }
          if (item != null)
          {
            IEnumIDList idEnum = null;
            try
            {
              item.EnumObjects(IntPtr.Zero, (ESHCONTF.SHCONTF_FOLDERS | ESHCONTF.SHCONTF_NONFOLDERS), ref idEnum);
            }
            catch (Exception ex)
            {
              Marshal.ReleaseComObject(folder);
              Allocator.Free(pidlMain);
              throw ex;
            }
            if (idEnum != null)
            {
              int hRes = 0;
              IntPtr pidl = IntPtr.Zero;
              int fetched = 0;
              bool complete = false;
              while (!complete)
              {
                hRes = idEnum.Next(1, ref pidl, ref fetched);
                if (hRes != 0)
                {
                  pidl = IntPtr.Zero;
                  complete = true;
                }
                else
                {
                  if (_getThumbNail(fileName, pidl, item))
                  {
                    complete = true;
                  }
                }
                if (pidl != IntPtr.Zero)
                {
                  Allocator.Free(pidl);
                }
              }
              Marshal.ReleaseComObject(idEnum);
            }
            Marshal.ReleaseComObject(item);
          }
          Allocator.Free(pidlMain);
        }
        Marshal.ReleaseComObject(folder);
      }
      return ThumbNail;
    }

    private bool _getThumbNail(string file, IntPtr pidl, IShellFolder item)
    {
      IntPtr hBmp = IntPtr.Zero;
      IExtractImage extractImage = null;
      try
      {
        string pidlPath = PathFromPidl(pidl);
        if (Path.GetFileName(pidlPath).ToUpper().Equals(Path.GetFileName(file).ToUpper()))
        {
          IUnknown iunk = null;
          int prgf = 0;
          Guid iidExtractImage = new Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1");
          item.GetUIObjectOf(IntPtr.Zero, 1, ref pidl, ref iidExtractImage, ref prgf, ref iunk);
          extractImage = (IExtractImage)iunk;
          if (extractImage != null)
          {
            Console.WriteLine("Got an IExtractImage object!");
            SIZE sz = new SIZE();
            sz.cx = DesiredSize.Width;
            sz.cy = DesiredSize.Height;
            StringBuilder location = new StringBuilder(260, 260);
            int priority = 0;
            int requestedColourDepth = 32;
            EIEIFLAG flags = EIEIFLAG.IEIFLAG_ASPECT | EIEIFLAG.IEIFLAG_SCREEN;
            int uFlags = (int)flags;
            try
            {
              extractImage.GetLocation(location, location.Capacity, ref priority, ref sz, requestedColourDepth, ref uFlags);
              extractImage.Extract(ref hBmp);
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {

            }
            if (hBmp != IntPtr.Zero)
            {
              _thumbNail = Bitmap.FromHbitmap(hBmp);
            }
            Marshal.ReleaseComObject(extractImage);
            extractImage = null;
          }
          return true;
        }
        else
        {
          return false;
        }
      }
      catch (Exception ex)
      {
        if (hBmp != IntPtr.Zero)
        {
          UnmanagedMethods.DeleteObject(hBmp);
        }
        if (extractImage != null)
        {
          Marshal.ReleaseComObject(extractImage);
        }
        throw ex;
      }
    }

    private string PathFromPidl(IntPtr pidl)
    {
      StringBuilder path = new StringBuilder(260, 260);
      int result = UnmanagedMethods.SHGetPathFromIDList(pidl, path);
      if (result == 0)
      {
        return string.Empty;
      }
      else
      {
        return path.ToString();
      }
    }

    private IShellFolder getDesktopFolder
    {
      get
      {
        IShellFolder ppshf = null;
        int r = UnmanagedMethods.SHGetDesktopFolder(ref ppshf);
        return ppshf;
      }
    }

    public void Dispose()
    {
      if (!disposed)
      {
        if (alloc != null)
        {
          Marshal.ReleaseComObject(alloc);
        }
        alloc = null;
        if (_thumbNail != null)
        {
          _thumbNail.Dispose();
        }
        disposed = true;
      }
    }
  }
}

К сожалению, вызовы миниатюр пакетов кода API Windows не поддерживаются в XP/2003.

Спасибо @Christian Nunciato, я хочу объяснить больше:

После установки WindowsAPICodePack-Shell набрав следующую команду в консоли Nuget:

Install-Package WindowsAPICodePack-Shell -Version 1.1.1

Прежде всего, вы должны знать, что это классное решение требует, чтобы вы установили соответствующую программу на сервере, например, если вы хотите, чтобы оболочка генерировала эскизы для файлов PDF, вы должны установить программу чтения PDF, такую ​​как Acrobat Reader или Foxit PhantomPDF, или что-то вроде их на сервере, это означает, что сервер будет создавать миниатюры для файлов, которые он их распознает, и это имеет смысл.

Во-вторых, проверьте, для каких расширений файлов создаются эскизы, другими словами, проверьте, имеют ли расширения файлов.psd или.msi правильные эскизы или нет, а затем запретите сервер запрашивать создание эскизов для них (проверьте как на стороне клиента, так и на сервере конец).

В-третьих, вам может потребоваться получить эскиз через Ajax, лично я предлагаю вам предоставить файлам несколько эскизов по умолчанию в зависимости от типа файла в первую секунду, а затем запросить сервер для создания эскиза, в этом случае вы можете использовать следующий фрагмент кода (я получаю сгенерированное растровое изображение в формате Base64 как изображение, которое на самом деле является строкой):

Код на стороне сервера:

[WebMethod]
public static string GetThumbnail(string path) {

    string thumb = string.Empty;

    path = @"D:\\" + path.Replace("/", "\\"); //Or Server.MapPath("/UploadedFiles");
    if (File.Exists(path))
    {
        try
        {
            Microsoft.WindowsAPICodePack.Shell.ShellFile shellFile = Microsoft.WindowsAPICodePack.Shell.ShellFile.FromFilePath(path);
            System.Drawing.Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
            MemoryStream ms = new MemoryStream();
            shellThumb.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);//Jpeg is preferred, Png would make a bigger file size
            thumb = Convert.ToBase64String(ms.ToArray());
        }
        catch(Exception ex)
        {

        }
    }
    return thumb;
}

Код на стороне клиента:

    var url = "Default.aspx/GetThumbnail",
        path = "Images/1.jpg",//For instance
        extension = path.split(".").pop().toLowerCase(),
        allowedExtensions = ["jpg", "jpeg", "png", "gif", "pdf", "mp4"];
    
    if (allowedExtensions.includes(extension)){
        $.ajax({
            type: 'POST',
            contentType: "application/json; charset=utf-8",
            url: url,
            data: "{'path':'" + path + "'}",
            async: true,
            xhrFields: {
                withCredentials: true
            },
            success: function (response) {
                if (!$.isEmptyObject(response.d))
                    $(elem).find("img").attr("src", "data:image/jpg;base64," + response.d);
            },
            error: function (err) {
                console.error(err);
            }
        });
    }

Учтите, что, поскольку возвращаемая строка может быть длинным текстом, вы можете столкнуться с ошибкой:

Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property base64

в этом случае вам нужно добавить следующий код в файл web.config:

  <system.web.extensions>
       <scripting>
           <webServices>
               <jsonSerialization maxJsonLength="2147483647"/>
           </webServices>
       </scripting>
   </system.web.extensions>

maxJsonLength - целочисленное значение и может быть Int32.MaxValue, вы можете прочитать больше здесь.

Не совсем то, что вы просили, но вот проект, чтобы открыть файл Thumbs.db.
Статья в Википедии содержит больше информации о том, где можно найти миниатюры в Vista & 7.

Вот код для получения изображения:

public byte[] GetThumbData(string filename)
{
    IStorageWrapper wrapper = new IStorageWrapper(_thumbDBFile, false);
    foreach(CatalogItem catItem in _catalogItems)
    {
        if (catItem.filename == filename)
        {
            string streamName = BuildReverseString(catItem.itemID);
            FileObject fileObject = wrapper.OpenUCOMStream(null, streamName);
            byte[] rawJPGData = new byte [fileObject.Length];
            fileObject.Read(rawJPGData, 0, (int)fileObject.Length);
            fileObject.Close();

            // 3 ints of header data need to be removed
            // Don't know what first int is.
            // 2nd int is thumb index
            // 3rd is size of thumbnail data.
            byte[] jpgData = new byte[rawJPGData.Length - 12];
            for (int index = 12; index < jpgData.Length; index++)
            {
                jpgData[index - 12] = rawJPGData[index];
            }
            return jpgData;
        }
    }
    return null;
}

public Image GetThumbnailImage(string filename)
{
    byte[] thumbData = GetThumbData(filename);
    if (null == thumbData)
    {
        return null;
    }
    MemoryStream ms = new MemoryStream(thumbData);
    Image img = Image.FromStream(ms);
    return img;
}

Вы должны использовать Windows GDI+, чтобы получить эти эскизы, как это.

Другие вопросы по тегам