C # Thumbnail aus Datei über Windows-API erhalten

74

Der Windows Explorer kann Miniaturansichten von Dateien anzeigen. Diese Miniaturansichten werden von Shell-Erweiterungen von Core- und Drittanbietern bereitgestellt.

Ich weiß, wie man die Shell erweitert, um Windows Miniaturansichten bereitzustellen.

Ich möchte das Miniaturbild aus einer beliebigen Datei im System über die Shell mit C # abrufen. Ist das möglich?

Im Wesentlichen schreibe ich einen benutzerdefinierten Dateibrowser und möchte Miniaturansichten anzeigen. Ich kann möglicherweise nicht jede Datei auf dem Planeten analysieren, um meine eigenen Miniaturansichten zu erstellen.

Erläuterung: Viele Antworten scheinen sich auf Miniaturansichten von Webseiten oder das Skalieren eines Bildes zu konzentrieren. Aber das ist überhaupt nicht das, wonach ich suche. Ich möchte Windows nach der Miniaturdarstellung dieser Dateitypen fragen: .DOC, .PDF, .3DM, .DWG ... und etwa ein Dutzend weitere. Ich möchte selbst keine Miniaturansichten analysieren, rendern und erstellen, da Windows bereits weiß, wie.

Der Code, den ich als Antwort gepostet habe, funktioniert tatsächlich ... vielleicht kann er vereinfacht und ein bisschen aufgeräumt werden.

Brian Gillespie
quelle
Bitte stellen Sie klar, dass Sie die Miniaturansicht der Datei und nicht das Symbol für den Dateityp (Erweiterung) möchten. Dass Sie nicht möchten Wie Sie die SHGetFileInfo-Funktion verwenden, um die Symbole abzurufen, die Dateien zugeordnet sind .
AMissico
Klarstellung basierend auf akzeptierter Antwort - Brian Gillespie möchte das Shell Thumbnail-Bild und nicht das Shell Icon-Bild.
AMissico

Antworten:

83

Ich bin heute darauf gestoßen - es ist ein paar Monate alt, aber es hat die Arbeit für mich erledigt (unter Win7, Extrahieren von Miniaturansichten in MPEG-4-Dateien):

Code:

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

Ich hoffe es hilft!

Christian Nuntius
quelle
2
Genial, danke Haufen ... habe mir den Code oben angesehen, meine Güte, muss es wirklich so schwer sein? Arbeitete ein Vergnügen! +1
Leichtgewicht
1
@Lightweight: Ja, es muss so schwer sein, weil auf dem Poster angegeben ist, dass sie keine Erweiterungen von Drittanbietern verwenden möchten und speziell die Shell verwenden möchten.
AMissico
1
Die Verwendung des API Code Pack von Microsoft ist eine viel einfachere Lösung. Meine akzeptierte Lösung ändern.
Brian Gillespie
Gutes Zeug. Das hat mir das Leben leichter gemacht.
Elan Hasson
4
Kann dies mit einem Stream anstelle eines zugeordneten Pfads erfolgen?
Sam Jones
19

Microsoft Office-Miniaturansichten in SharePoint unter http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx . ist genau das, was Sie wollen. (Ich hatte keine Probleme, den VB.NET-Code mithilfe von http://www.developerfusion.com/tools/convert/vb-to-csharp/ in C # zu konvertieren.)

In Bezug auf den Code, den Sie in Ihrer Antwort veröffentlicht haben, ist die Miniaturansicht mithilfe der Shell unter http://www.vbaccelerator.com/home/net/code/libraries/Shell_Projects/Thumbnail_Extraction/article.asp der Originalartikel, aus dem der Code stammt. Ich glaube, dass fast alle IExtractImageBeispiele (Sie finden die Suche) auf dem Code dieses Artikels basieren, aufgrund von Namenskonventionen, Kommentaren usw., die aus dem Original stammen. Da dieser Artikel aus dem April 2003 stammt, enthält er einige nicht standardmäßige (non.NET) Codierungskonventionen. Ich habe einige grundlegende Tests durchgeführt, und es gibt Probleme bei der Speicherbereinigung, bei der Freigabe nicht verwalteter Ressourcen und bei anderen Bereinigungsproblemen. Daher empfehle ich dringend, den Code in diesem Artikel zu vermeiden. Darüber hinaus ist der Code so strukturiert, dass die Wartung schwierig wird.

Es gibt eine sauberere, einfachere Version von MSDN vom Juli 2005 mit dem Namen Microsoft Office Thumbnails in SharePoint unter http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx . Dieser Code und der Code des Artikels haben Ähnlichkeiten, was mich zu der Annahme führt, dass die Miniaturansicht mit dem Shell- Artikel die Grundlage für den SharePoint- Artikel ist. Die VB.NET-Version von GetThumbnailImageignoriert den longestEdgeParameter, die C ++ - Version verwendet ihn jedoch und dokumentiert die Verwendung der Flags ORIGSIZEund QUALITY. Darüber hinaus zeigt der Code, wie .NETs FreeCoTaskMemanstelle der Shell's IMallocund verwendet werden SHGetMalloc.

IExtractImagefunktioniert mit Dateien, Ordnern und anderen Namespace-Objekten. Der MSDN-Code funktioniert mit versteckten Dateien, während der vbAccelerator-Code dann SHCONTF_INCLUDEHIDDENzum EnumObjectsAufruf hinzugefügt werden muss . Darüber hinaus listet der vbAccelerator die Objekte des Shell-Ordners auf und sucht nach der angegebenen Datei. Dies scheint Zeitverschwendung zu sein. Dies war möglicherweise erforderlich, um die richtige "relative" PIDL zu finden, die für den GetUIObjectOfAufruf verwendet wird.


ShellThumbnail (in Arbeit)

Schließen Sie das Beispielprojekt unter http://cid-7178d2c79ba0a7e3.office.live.com/self.aspx/.Public/ShellThumbnail.zip ab .

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
quelle
AMissico - danke dafür. Ich habe Ihren Code nicht getestet, aber Ihre Argumentation scheint zutreffend zu sein. Daher akzeptiere ich Ihre Antwort als die richtige und nicht als die, die ich bei EE gefunden habe.
Brian Gillespie
Danke für das Beispielprojekt, AMissico. Sie sollten in Betracht ziehen, es auf CodePlex oder GoogleCode zu setzen, damit andere es überprüfen und Verbesserungen einreichen können.
Dthrasher
1
Außerdem habe ich Ihr Projekt mit dem anderen Code auf vbaccelerator getestet. Ihre Leistung ist etwas schneller. (Ich nehme Ihr Wort zu den Speicherproblemen.)
Dthrasher
Die Leistungssteigerung hängt wahrscheinlich damit zusammen, dass die Codes nicht über die Objekte des Shell-Ordners aufgelistet werden. Der Code ist im Wesentlichen der gleiche.
AMissico
2
@dthrasher, ich bemerke neulich aus den FTP-Protokollen, dass das Projekt einige Male pro Woche heruntergeladen wird. Nachdem ich ein Haustierprojekt abgeschlossen habe, plane ich, ein Testprojekt zu erstellen und den Code in CodeProject oder CodePlex zu veröffentlichen.
AMissico
3

Hier ist eine Klasse, die ich im Internet gesucht habe. Es sieht so aus, als ob der ursprüngliche Code von http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21789724.html stammt , aber ich kann ihn nicht sehen, um ihn richtig zuzuordnen. Ich habe die Quelle hier gefunden: http://www.vbforums.com/showthread.php?t=527704

Hier ist eine Klasse mit den richtigen COM-Aufrufen, die hier für die Nachwelt wiedergegeben wird:


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;
      }
    }
  }
}
Brian Gillespie
quelle
3
Um eine EE-Seite anzuzeigen, kopieren Sie die URL, gehen Sie zu Google, suchen Sie danach, klicken Sie auf das Ergebnis, scrollen Sie nach unten und es gibt die Antworten. Sie sollten von Google verboten werden ....
Corymathews
Wenn Sie die Google Toolbar installiert haben, klicken Sie mit der rechten Maustaste auf die Seite in der betreffenden Domain und wählen Sie Seiteninfo -> Zwischengespeicherter Snapshot der Seite, um zu sehen, welche Dienste Google beim Crawlen dort zur Verfügung gestellt hat.
Matthew Lock
1
Dies ist eine SEHR komplizierte Methode zur Verwendung von GDI + in C #, da ein C # -Wrapper für GDI + im DotNet-Framework enthalten ist.
Eran Betzalel
Ich glaube, dass die Miniaturansicht mithilfe der Shell unter vbaccelerator.com/home/net/code/libraries/Shell_Projects/… der Originalartikel ist, aus dem der Code stammt. Ich fand, dass der Code von der ungewöhnlichen Art und Weise, wie die Enums benannt wurden, wie EIEIFLAG, vertraut aussah. Es stammt aus dem April 2003.
AMissico
Hier ist eine sauberere, einfachere Version ab Juli 2005. Microsoft Office-Miniaturansichten in SharePoint unter msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx . Dieser Code und der Code des Artikels haben Ähnlichkeiten. (Es sieht so aus, als ob die Miniaturansicht mit dem Shell- Artikel die Grundlage für den SharePoint-Artikel ist.)
AMissico
1

Die Miniaturansichten des Windows API Code Packs werden von XP / 2003 leider nicht unterstützt.

Andrew Gale
quelle
0

Nicht genau das, was Sie gefragt haben, aber hier ist ein Projekt zum Öffnen einer Thumbs.db-Datei .
Der Wikipedia-Artikel enthält weitere Informationen dazu, wo Sie in Vista und 7 Miniaturansichten finden.

Hier ist der Code, um das Bild zu erhalten:

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;
}
Hemisphire
quelle
Link ist unterbrochen, aber jemand kennt zufällig die Verschlüsselung pw auf dem Daumen-Cache .db?
ThomasRones
Der Link wurde behoben. Es scheint kein Passwort zu geben. Ich habe meiner Antwort den entsprechenden Code hinzugefügt.
Hemisphire
0

Dank @Christian Nunciato möchte ich mehr erklären:

Nach der Installation geben Sie den WindowsAPICodePack-Shellfolgenden Befehl in die Nuget-Konsole ein:

Install-Package WindowsAPICodePack-Shell -Version 1.1.1

Zunächst sollten Sie wissen, dass Sie für diese coole Lösung ein entsprechendes Programm auf dem Server installieren müssen. Wenn Sie beispielsweise möchten, dass die Shell Miniaturansichten für PDF-Dateien generiert, sollten Sie einen PDF-Reader wie Acrobat Reader oder Foxit PhantomPDF oder ähnliches installieren Wenn sie sich auf dem Server befinden, bedeutet dies, dass der Server eine Miniaturansicht für Dateien erstellt, die er erkennt, und dies ist sinnvoll.

Überprüfen Sie zweitens , für welche Dateierweiterungen Miniaturansichten generiert wurden. Überprüfen Sie mit anderen Worten, ob die Dateierweiterungen .psd oder .msi über die richtigen Miniaturansichten verfügen oder nicht, und verhindern Sie dann, dass der Server aufgefordert wird, Miniaturansichten für diese zu generieren (überprüfen Sie sowohl das Client-Ende als auch den Server Ende).

Drittens müssen Sie möglicherweise eine Miniaturansicht über Ajax abrufen. Ich persönlich empfehle Ihnen, den Dateien in der ersten Sekunde einige Standard-Miniaturansichten basierend auf dem Dateityp zu geben und dann den Server zum Generieren der Miniaturansicht anzufordern. In diesem Fall können Sie das folgende Code-Snippet verwenden (ich erhalte) die generierte Bitmap im Base64-Format als Bild (eigentlich Zeichenfolge):

Serverseitiger Code:

[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;
}

Client-seitiger Code:

    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);
            }
        });
    }

Beachten Sie, dass, da die zurückgegebene Zeichenfolge möglicherweise ein langer Text ist, möglicherweise ein Fehler auftritt, der besagt:

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

In diesem Fall müssen Sie folgenden Code in die Datei web.config einfügen:

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

maxJsonLength ist ein ganzzahliger Wert und kann Int32.MaxValue sein. Weitere Informationen finden Sie hier .

Muhammad Musavi
quelle
-3

Sie sollten die Windows - GDI + verwenden , um diese Thumbnails zu bekommen, wie diese .

Eran Betzalel
quelle
Das ist zwar eine kurze süße Antwort, aber sie macht nicht das, was ich brauche. Es funktioniert nur für .jpg, .gif, .png, .bmp und alle anderen Dateien, die in .NET unterstützt werden. Wenn Sie den Code lesen, den Sie als komplex bezeichnet haben, werden Sie feststellen, dass er tatsächlich die IExtractImage-Methode in einem COM-Objekt mit der GUID {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} aufruft. Dies ist viel mehr als nur das Skalieren eines Bildes.
Brian Gillespie
Die von mir vorgestellte DotNet-Komponente verwendet GDI +, das direkt von Win32API stammt. Dies bedeutet, dass diese Komponente alles unterstützt, was das Betriebssystem unterstützt. Wenn die Anzahl der vom Betriebssystem unterstützten Dateitypen nicht Ihren Anforderungen entspricht, sollten Sie nach einem Modul eines Drittanbieters suchen, um Ihre Bilder zu verarbeiten.
Eran Betzalel
1
GDI + unterstützt beispielsweise keine PDFs oder Photoshop-PSDs. Dritte können Handler bei der Shell registrieren. GDI + kommuniziert nicht mit COM-Objekten von Drittanbietern.
Ian Boyd
Ich denke du hast mich falsch verstanden. Verwenden Sie GDI + / Win32API, wenn es die benötigten Dateitypen unterstützt, wenn dies nicht der Fall ist - verwenden Sie Komponenten von Drittanbietern.
Eran Betzalel