2012-09-29 11 views
11

Ich habe eine Anwendung erstellt, die Ihnen eine Liste von Dateien auf Ihrem Computer präsentiert. Wenn Sie auf ein Element in der Liste klicken, sollte eine kleine PictureBox neben der Miniaturansicht der entsprechenden Datei angezeigt werden. Ich verwende C# unter Windows 7.Zugriff auf Thumbnails, die nicht existieren

Um das Thumbnail zu erhalten, habe ich eine Methode in einer anderen Frage wiederholt. Zuerst referenziere ich das Windows API Code Pack. Dann benutze ich den folgenden Code:

ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile); 
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap; 

Dies funktioniert nicht immer. Manchmal ist das angezeigte Miniaturbild lediglich das Symbol für die Standardanwendung. Ich habe herausgefunden, dass das echte Thumbnail nur angezeigt wird, wenn Windows zuvor das Thumbnail für diese Datei generiert und im Thumbnails-Cache gespeichert hat. Das bedeutet, dass ich einen Ordner manuell öffnen muss, auf Windows warten muss, um Miniaturen für jede Datei zu erstellen, und dann wird meine Anwendung diese Daumen sehen können.

Wie kann mein Programm Windows 7 zwingen, echte Miniaturansichten zu erstellen, bevor Sie sie verwenden?

Update (von Li0liQ)

Es ist möglich, durch Thumbnail-Retrieval zu zwingen FORMAT Zugabe:

ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile); 
shellFile.Thumbnail.FormatOption = ShellThumbnailFormatOption.ThumbnailOnly; 
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap; 

aber ich bin immer eine Ausnahme im Fall Thumbnail noch nicht da ist:

Das aktuelle ShellObject hat keinen gültigen Thumbnail-Handler oder Es gab ein Problem beim Extrahieren des Thumbnails für dieses spezifische Shell-Objekt. ---> System.Runtime.InteropServices.COMException: Klasse nicht registriert (Ausnahme von HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

Siehe How do I refresh a file's thumbnail in Windows Explorer? Frage und Code snippet für mögliche Hinweise.

+1

li0liq, Ihre Fehlermeldung sagt nicht, dass das Thumbnail noch nicht da ist, es heißt, es gibt keinen Handler, um das Thumbnail zu erzeugen. –

Antwort

-1

Soweit ich weiß, können Sie Windows 7 nicht zwingen, Thumbnails zu erstellen. Allerdings können Sie es mit dem Code selbst erstellen:

Image image = Image.FromFile(fileName); 
Image thumbNail = image.GetThumbnailImage(120, 120,()=>false, IntPtr.Zero); 
thumbNail.Save(Path.ChangeExtension(fileName, "thumb")); 

http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx

+1

Die Frage ist ein bisschen breiter als das Erstellen einer Miniatur für ein Bild. Ein generischer Ansatz ist erforderlich oder zumindest der, der das Erstellen eines Miniaturbildes für ein neu erstelltes PDF-Dokument ermöglicht. – Li0liQ

0

Nach einiger Suche finde ich Microsoft Office Thumbnails in Sharepoint. Es funktioniert möglicherweise nur mit Office-Dokumenten, aber möglicherweise was Sie wollen. Wird eine Übersetzung erfordern, wie die Beispiele in C++ und VB.Net sind.

+0

Der im Artikel vorgeschlagene Ansatz ist ein Low-Level-Äquivalent der beiden Codezeilen in der Frage und schlägt mit genau der gleichen Ausnahme fehl: 0x80040154 (REGDB_E_CLASSNOTREG) - was ungefähr bedeutet "noch keine Miniaturansicht verfügbar". – Li0liQ

0

Wie kann mein Programm Windows 7 zwingen, echte Miniaturansichten zu erstellen, bevor Sie sie verwenden?

Von Shell Schnittstellen: zum Abrufen und Cache Thumbnails IThumbnailCache interface (Hervorhebung von mir)

Die Thumbnail-Cache-API ist so konzipiert, Anwendungen mit einem einheitlichen Verfahren zu schaffen. In Windows XP Thumbnail-Caching wird auf einer pro-Ordner-Basis durchgeführt, und der Cache ist in einer Thumbs.db-Datei in jedem Ordner verwaltet. Während dieser Ansatz räumliche Lokalität bietet, unterstützt es keine Vorschau und Abfragen über Ordner hinweg.Der Thumbnail-Cache in Windows Vista behebt diesen Mangel, indem ein globaler Cache bereitgestellt wird.

ein Thumbnail cachen, eine Anwendung muss zuerst eine IShellItem erhalten, den das Element darstellt , für die eine Miniatur erhalten wird, und dann die IShellItem zu einem Aufruf an IThumbnailCache :: GetThumbnail passieren. Wenn der Flags-Parameter zu IThumbnailCache :: GetThumbnail das Flag WTS_EXTRACT enthält und das Thumbnail nicht bereits zwischengespeichert ist, wird ein Thumbnail extrahiert und in den Cache gestellt. Wenn das Flag WTS_FORCEEXTRACTION gesetzt ist, wird der Cache ignoriert und ein neues Thumbnail wird immer extrahiert. Weitere Informationen zu den Flags , die an IThumbnailCache :: GetThumbnail übergeben wurden, finden Sie unter dem Thema IThumbnailCache :: GetThumbnail.

Wenn ein Miniaturbild nicht bereits im Cache ist, wird er automatisch aus der Quelldatei extrahiert werden die vorhandenen Implementierung unter Verwendung (en) von IExtractImage oder IThumbnailProvider, die auf dem Betriebssystem registriert ist. Ihre Anwendung muss keine Implementierung des Miniaturansichtsextraktors bereitstellen.

Also, Ihr System unter der Annahme hat eine Implementierung von IThumbnail-Anbieter, der mit PDF funktioniert:

  1. ein Shell-Element für Ihre PDF-Get.
  2. Erhalten Sie einen Verweis auf den Thumbnail-Cache der Shell. Nennen wir es thumbNailCache.
  3. Anruf thumbNailCache.GetThumbnail(shellItem, thumbNailpx,wtxFlagSet, out thumbNailBitmap);. Die Dokumentation besagt, dass dies das Thumbnail für Sie erstellt und im out-Parameter thumbNailBitmap zurückgibt.

Caveats: Ich weiß nicht, ob Ihr Code Paket IThumbnailCache vollständig aussetzt, aber wenn es der Fall ist, sieht das ziemlich geradlinig sein. Wenn dies nicht der Fall ist, müssen Sie es von der Shell32.dll importieren.

Es gibt auch eine IThumbnailProvider Schnittstelle, die für Sie arbeiten kann, aber lesen Sie die Community-Kommentare. Es scheint zerbrechlich und knifflig zu sein.

+0

Können Sie ein Codebeispiel geben, wie Sie ein Shell-Objekt erhalten und den Thumbnail-Cache erhalten? –

3

Hier ist ein Code, der Thumbnail-Bitmaps extrahiert (nur Windows Vista oder höher). Es basiert auf dem kühlen IShellItemImageFactory interface:

static void Main(string[] args) 
    { 
     // you can use any type of file supported by your windows installation. 
     string path = @"c:\temp\whatever.pdf"; 
     using (Bitmap bmp = ExtractThumbnail(path, new Size(1024, 1024), SIIGBF.SIIGBF_RESIZETOFIT)) 
     { 
      bmp.Save("whatever.png", ImageFormat.Png); 
     } 
    } 

    public static Bitmap ExtractThumbnail(string filePath, Size size, SIIGBF flags) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException("filePath"); 

     // TODO: you might want to cache the factory for different types of files 
     // as this simple call may trigger some heavy-load underground operations 
     IShellItemImageFactory factory; 
     int hr = SHCreateItemFromParsingName(filePath, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out factory); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     IntPtr bmp; 
     hr = factory.GetImage(size, flags, out bmp); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     return Bitmap.FromHbitmap(bmp); 
    } 

    [Flags] 
    public enum SIIGBF 
    { 
     SIIGBF_RESIZETOFIT = 0x00000000, 
     SIIGBF_BIGGERSIZEOK = 0x00000001, 
     SIIGBF_MEMORYONLY = 0x00000002, 
     SIIGBF_ICONONLY = 0x00000004, 
     SIIGBF_THUMBNAILONLY = 0x00000008, 
     SIIGBF_INCACHEONLY = 0x00000010, 
     SIIGBF_CROPTOSQUARE = 0x00000020, 
     SIIGBF_WIDETHUMBNAILS = 0x00000040, 
     SIIGBF_ICONBACKGROUND = 0x00000080, 
     SIIGBF_SCALEUP = 0x00000100, 
    } 

    [DllImport("shell32.dll", CharSet = CharSet.Unicode)] 
    private static extern int SHCreateItemFromParsingName(string path, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemImageFactory factory); 

    [ComImport] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")] 
    private interface IShellItemImageFactory 
    { 
     [PreserveSig] 
     int GetImage(Size size, SIIGBF flags, out IntPtr phbm); 
    } 

Zusätzliche Hinweise:

  • Die GetImage Methode verschiedene interessante Flags (SIIGBF) ist, können Sie spielen mit.
  • Aus Leistungsgründen können Sie die Fabriken zwischenspeichern. Für .PDF-Dateien muss beispielsweise der gesamte Adobe Reader .exe im Hintergrund geladen werden.
  • Wenn Sie mit der Shell (Windows Explorer) sprechen, möchten Sie sicherstellen, dass Ihr Prozess UAC-Ebene als die Shell ausgeführt wird. Anderenfalls schlagen einige Operationen aus Sicherheitsgründen fehl.Wenn Sie Ihren Prozess beispielsweise in Visual Studio von F5 oder STRG + F5 aus ausführen und Visual Studio als Administrator ausgeführt wird, kann Ihr Prozess möglicherweise keine Miniaturansichten abrufen, während er bei Doppelklick auf die EXE-Datei funktioniert vom Entdecker. Die REGDB_E_CLASSNOTREG ist eine typische Art von Fehler, den Sie in diesen Fällen erhalten können.
+0

Ich bekomme ein "System konnte die angegebene Datei nicht finden" beim ersten 'Win32Exception (hr)' Aufruf. Wenn ich 'FileExists (filePath)' aufruft, bekomme ich 'True'. – Scott

+0

Aber wenn ich 'PathResolve' von Shell32 importiere, sagt es mir, dass die Datei NICHT da ist .... – Scott