C#通过Windows API从文件获取缩略图


75

Windows资源管理器具有显示文件缩略图的功能。这些缩略图由核心和第三方Shell扩展提供。

我知道如何扩展外壳以向Windows提供缩略图。

我想做的是使用C#通过外壳从系统上的任何文件中检索缩略图。这可能吗?

本质上,我正在编写一个自定义文件浏览器,并且想要显示缩略图,并且无法解析地球上的每个文件来制作自己的缩略图。

说明:许多答案似乎都围绕网页缩略图或缩放图像。但这根本不是我想要的。我想要的是询问Windows这些文件类型的缩略图表示:.DOC,.PDF,.3DM,.DWG ...和mabye,还有十几种。我不想自己解析,渲染和制作缩略图,因为Windows已经知道如何操作。

我作为答案发布的代码实际上是有效的……也许可以对其进行简化和清理。


请说明您要文件的缩略图,而不是文件类型(扩展名)的图标。您不希望如何使用SHGetFileInfo函数来获取与文件关联的图标
2009年

根据接受的答案进行说明-Brian Gillespie想要Shell Thumbnail图像而不是Shell Icon图像。
AMissico 2010年

Answers:


83

今天遇到了这个问题-已有几个月的历史了,但是它为我完成了工作(在Win7上,提取MPEG-4文件的缩略图):

码:

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

希望能帮助到你!


2
Awesom,感谢堆...正在查看geez上面的代码,真的真的必须那么难。工作了请客!+1
轻量级游戏

1
@轻量级:是的,必须这么难,因为发布者指出他们不想使用第三方扩展,而他们特别想使用命令行管理程序。
2011年

1
使用Microsoft的API代码包是一种更为简单的解决方案。更改我接受的解决方案。
Brian Gillespie 2012年

好东西。这使我的生活更加轻松。
伊兰·哈森

4
可以使用流而不是映射路径来完成此操作吗?
山姆·琼斯

19

SharePoint中的Microsoft Office缩略图,位于http://msdn.microsoft.com/zh-cn/library/aa289172(VS.71).aspx正是您想要的。(使用http://www.developerfusion.com/tools/convert/vb-to-csharp/将VB.NET代码转换为C#时,我没有遇到任何麻烦。)

关于您在答案中发布的代码,http://www.vbaccelerator.com/home/net/code/libraries/Shell_Projects/Thumbnail_Extraction/article.asp上的使用Shell进行缩略图提取是该代码的原始文章。我相信由于命名约定,注释等原因,几乎所有样本(您在搜索中都基于本文)基于原始代码而带。自从本文发布于2003年4月以来,它带有一些非标准(non.NET)编码约定。我进行了一些基本测试,发现了垃圾回收问题,释放了非托管资源问题以及其他清理问题。因此,我强烈建议您避免使用该文章中的代码。而且,代码的结构化是使维护变得困难的一种方式。IExtractImage

MSDN上有一个干净简单的版本(日期为2005年7月),在http://msdn.microsoft.com/zh-cn/library/aa289172(VS.71).aspx上称为SharePoint中的Microsoft Office缩略图此代码与本文的代码具有相似之处,这使我相信使用Shell进行缩略图提取SharePoint文章的基础。VB.NET版本GetThumbnailImagelongestEdge参数会忽略,但C ++版本会使用该参数并记录ORIGSIZEQUALITY标志的使用。此外,该代码还说明了如何使用.NETFreeCoTaskMem而不是Shell的IMallocand SHGetMalloc

IExtractImage与文件,文件夹和其他命名空间对象一起使用。MSDN代码可用于隐藏文件,而vbAccelerator代码则需要SHCONTF_INCLUDEHIDDEN添加到EnumObjects调用中。另外,vbAccelerator枚举shell文件夹的对象以查找指定文件,这似乎很浪费时间。可能需要找到用于GetUIObjectOf调用的正确“相对” PIDL 。


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

AMissico-谢谢。我尚未测试您的代码,但您的推理似乎正确,因此,我将接受您的答案是正确的答案,而不是我在EE上找到的答案。
布莱恩·吉莱斯皮

感谢您的示例项目AMissico。您应该考虑将其放在CodePlex或GoogleCode上,以便其他人可以检查它并提交改进。
dthrasher 2010年

1
另外,我已经针对vbaccelerator上的其他代码测试了您的项目。您的执行速度稍快。(我会对您在内存问题上的
承诺

性能提高可能与缺少枚举Shell文件夹的对象的代码有关。代码本质上是相同的。
AMissico 2010年

2
@dthrasher,前几天我从ftp日志中注意到该项目每周要下载几次。完成宠物项目后,我计划创建一个测试项目并将代码发布到CodeProject或CodePlex。
AMissico 2010年


3

这是我在互联网上搜索到的一门课。原始代码似乎来自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;
      }
    }
  }
}

3
要查看EE页面,请复制该URL,转到google,进行搜索,单击结果,滚动到底部,然后找到答案。他们应该被禁止从谷歌
。...– corymathews

如果您安装了Google工具栏,请在相关域中的页面上单击鼠标右键,然后选择“页面信息”->“页面的缓存快照”,以查看它们在Google那里进行爬网时为谷歌提供的服务。
马修·洛克

1
这是在C#中使用GDI +的非常复杂的方法,因为DotNet框架中包含GDI +的C#包装器。
Eran Betzalel 09年

我相信vShellcelerator.com/home/net/code/libraries/Shell_Projects/…上的使用Shell进行缩略图提取是代码的原始文章。我认为该代码看起来像Enum的不寻常命名方式(例如EIEIFLAG)一样。它的日期从2003
。– AMissico 2009年

这是自2005年7月以来的较简单版本。SharePoint中的Microsoft Office缩略图位于msdn.microsoft.com/zh-cn/library/aa289172(VS.71).aspx。此代码与文章的代码具有相似之处。(看起来“使用Shell进行缩略图提取”是SharePoint文章的基础。)
AMissico,2009年


0

并非您所要求的完全一样,但这是一个打开Thumbs.db文件的项目
Wikipedia文章提供了有关在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;
}

链接断开了,但是谁碰巧知道拇指缓存.db上的加密密码?
ThomasRones

修复了链接。似乎没有密码;我在答案中添加了适用的代码。
hemisphire

0

感谢@Christian Nunciato,我想进一步说明:

WindowsAPICodePack-Shell在Nuget控制台中键入以下命令进行安装后:

Install-Package WindowsAPICodePack-Shell -Version 1.1.1

首先,您应该知道这个很酷的解决方案需要您在服务器上安装相关程序,例如,如果您希望外壳程序为PDF文件生成缩略图,则应该安装PDF阅读器,例如Acrobat ReaderFoxit 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,您可以在此处阅读更多内容。


这在Windows 10或Windows Server 2016上适合您吗?对我来说,它仅在Windows 7中提供docx和pdf的预期结果。对于图像没有问题。
史密斯女士

我在Windows Server 2016 Datacenter上使用以上代码创建了一种DMS(文档管理系统),因此它可以正常工作。
Muhammad Musavi

-3

您应该使用Windows GDI +获得这些缩略图,像这样


虽然这是一个简短的好答案,但它并不能满足我的需求。它仅适用于.jpg,.gif,.png,.bmp以及.NET支持的任何其他文件。如果您通读称为复杂的代码,则会发现它实际上是在GUID {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}的某个COM对象中调用IExtractImage方法。这不仅涉及缩放图像,还涉及更多的内容。
Brian Gillespie

我介绍的DotNet组件使用直接来自Win32API的GDI +,这意味着该组件支持操作系统支持的所有功能。如果操作系统支持的文件类型数量不符合您的需求,则应寻找第三方模块来处理图像。
Eran Betzalel 09年

1
GDI +不支持,例如PDF或Photoshop PSD。第三方可以在shell中注册处理程序;GDI +不与第三方COM对象对话。
伊恩·博伊德

我想你误会了我。如果GDI + / Win32API支持所需的文件类型,则使用GDI + / Win32API;否则,请使用-第三方组件。
Eran Betzalel 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.