代码之家  ›  专栏  ›  技术社区  ›  Brian Gillespie

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

  •  66
  • Brian Gillespie  · 技术社区  · 15 年前

    Windows资源管理器可以显示文件的缩略图。这些缩略图由核心和第三方外壳扩展提供。

    我知道如何扩展外壳来为窗口提供缩略图。

    我要做的是使用c_通过shell从系统上的任何文件中检索缩略图。这有可能吗?

    实际上,我正在编写一个自定义的文件浏览器,我想显示缩略图,而且不可能解析地球上的每个文件来制作自己的缩略图。

    澄清: 许多答案似乎集中在网页缩略图或缩放图像上。但这根本不是我想要的。我想要的是要求Windows提供这些文件类型的缩略图表示形式:.doc、.pdf、.3dm、.dwg…马拜还有十几个。我不想自己分析、渲染和制作缩略图,因为Windows已经知道如何操作了。

    我作为答案发布的代码实际上是有效的…也许它可以简化和清理一点。

    7 回复  |  直到 6 年前
        1
  •  73
  •   Robin Rodricks    7 年前

    今天遇到了这个问题——它已经存在几个月了,但它为我完成了任务(在Win7上,提取MPEG-4文件上的缩略图):

    代码:

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

    希望有帮助!

        2
  •  18
  •   AMissico    14 年前

    SharePoint中的Microsoft Office缩略图 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年4月,所以它带有一些非标准(非.NET)编码约定。我做了一些基本测试,有垃圾收集问题、释放未管理的资源问题和其他清理问题。因此,我强烈建议避免本文中的代码。此外,代码的结构化也是一种使维护变得困难的方式。

    在2005年7月的msdn上有一个干净、简单的版本,叫做 SharePoint中的Microsoft Office缩略图 http://msdn.microsoft.com/en-us/library/aa289172(vs.71).aspx . 这段代码和文章的代码有相同之处,这让我相信 使用外壳提取缩略图 文章是 共享点 文章。的vb.net版本 GetThumbnailImage 忽视 longestEdge 参数,但C++版本使用它并记录使用 ORIGSIZE QUALITY 旗帜。此外,该代码演示了如何使用.NET FreeCoTaskMem 而不是贝壳的 IMalloc SHGetMalloc .

    自我抽取 用于文件、文件夹和其他命名空间对象。msdn代码用于隐藏文件,而vbeAccelerator代码则需要 SHCONTF_INCLUDEHIDDEN 添加到 EnumObjects 打电话。此外,vbeAccelerator枚举shell文件夹的对象以查找指定的文件,这似乎是浪费时间。这可能是为了找到用于 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
    
        3
  •  7
  •   John Gietzen    15 年前

    这可能有帮助:

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

    这包括shell API,并允许您执行shell可以执行的几乎所有操作(包括呈现缩略图)。

        4
  •  3
  •   Brian Gillespie    15 年前

    这是我在网上找到的一个班级。看起来原始代码来自 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;
          }
        }
      }
    }
    
        5
  •  1
  •   Andrew Gale    12 年前

    不幸的是,XP/2003不支持Windows API代码包缩略图调用。

        6
  •  0
  •   hemisphire Valeriy Katkov    6 年前

    不完全是你要的,但是 here's a project to open a Thumbs.db file .
    The Wikipedia article has more information 在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;
    }
    
        7
  •  -2
  •   Eran Betzalel    15 年前

    您应该使用Windows GDI+获取这些缩略图,比如 this .