2009-01-20 3 views
42

In. Net (C# oder VB: egal), eine Datei Pfad Zeichenfolge, FileInfo Struct oder FileSystemInfo Struct für eine real existierende Datei, wie kann ich das Symbol (e) bestimmen von der Shell (Explorer) für diese Datei verwendet?Get-Datei-Symbol von Shell verwendet

Ich plane derzeit nicht, dies für irgendetwas zu verwenden, aber ich wurde neugierig, wie man es macht, wenn man this question betrachtet und ich dachte, dass es nützlich wäre, hier auf SO archiviert zu haben.

Antwort

50
Imports System.Drawing 
Module Module1 

    Sub Main()  
     Dim filePath As String = "C:\myfile.exe" 
     Dim TheIcon As Icon = IconFromFilePath(filePath) 

     If TheIcon IsNot Nothing Then  
      ''#Save it to disk, or do whatever you want with it. 
      Using stream As New System.IO.FileStream("c:\myfile.ico", IO.FileMode.CreateNew) 
       TheIcon.Save(stream)   
      End Using 
     End If 
    End Sub 

    Public Function IconFromFilePath(filePath As String) As Icon 
     Dim result As Icon = Nothing 
     Try 
      result = Icon.ExtractAssociatedIcon(filePath) 
     Catch ''# swallow and return nothing. You could supply a default Icon here as well 
     End Try 
     Return result 
    End Function 
End Module 
+0

Das ist für .exes in Ordnung, .dlls oder andere Dateien, die Symbole enthalten. Aber was ist mit Textdateien oder anderen einfachen Dateien, bei denen das Symbol je nach installiertem Programm oder einer vom Benutzer geänderten Einstellung variieren kann? –

+0

Es sollte für ALLE Dateien funktionieren, die ein zugehöriges Icon haben, es muss kein assoziiertes Programm haben, was ich weiß. – Stefan

+0

Was wird zurückgegeben, wenn kein Symbol zugeordnet ist? –

0

This Link scheint einige Informationen zu haben. Es beinhaltet eine Menge Registry-Traversing, aber es scheint machbar. Die Beispiele sind in C++

0
  • bestimmen Erweiterung
  • in der Registry, gehen Sie zu "HKCR\.{extension}", den Standardwert lesen (die es filetype rufen lassen)
  • in "HKCR\{filetype}\DefaultIcon", lesen Sie den Standardwert: Dies ist der Pfad zu dem icon-Datei (oder das Symbol Container-Datei, wie ein EXE mit einer eingebetteten Symbol Ressource)
  • , wenn nötig, verwenden Sie Ihre bevorzugte Methode der Extraktion die Symbolressource aus der genannten Datei

Bearbeiten/aus den Kommentaren verschoben:

Wenn das Symbol in einer Container-Datei ist (das ist ziemlich häufig), wird ein Zähler nach dem Pfad angezeigt, wie folgt: "foo.exe,3". Dies bedeutet, dass das Symbol Nr. 4 (der Index ist auf Null basiert) der verfügbaren Symbole besteht. Ein Wert von ", 0" ist implizit (und optional). Wenn der Zähler 0 ist oder fehlt, wird das erste verfügbare Symbol von der Shell verwendet.

+0

Wenn es eine Symbolcontainerdatei ist, die mehrere Symbole enthält, woher wissen Sie dann, welche verwendet werden soll? –

+0

Es gibt einen Zähler hinter dem Pfad, wie "foo.exe, 3". Dies bedeutet, dass es Symbol Nr. Ist. 4 (der Index ist nullbasiert) der verfügbaren Symbole. Ein Wert von ", 0" ist implizit und daher optional. Wenn es fehlt, wird das erste verfügbare Symbol von der Shell verwendet. – Tomalak

+2

Die Registrierung ist keine API! Es gibt andere Möglichkeiten, Symbole anzugeben, und diese Methode ist falsch. Bitte verwenden Sie hierfür die SHGetFileInfo API. – Tron

15

Bitte ignorieren Sie alle, die Ihnen sagen, dass Sie die Registrierung verwenden! Die Registrierung ist keine API. Die gewünschte API ist SHGetFileInfo mit SHGFI_ICON. Sie können hier eine P/Invoke Signatur erhalten:

http://www.pinvoke.net/default.aspx/shell32.SHGetFileInfo

+3

Da wir nach C# oder VB sind, ist Stefans Antwort viel einfacher. –

15

Sie sollten SHGetFileInfo verwenden.

Icon.ExtractAssociatedIcon funktioniert in den meisten Fällen genauso gut wie SHGetFileInfo, aber SHGetFileInfo kann mit UNC-Pfaden arbeiten (z. B. ein Netzwerkpfad wie "\\ ComputerName \ SharedFolder \"), während Icon.ExtractAssociatedIcon nicht kann. Wenn Sie UNC-Pfade benötigen oder benötigen, empfiehlt es sich, SHGetFileInfo anstelle von Icon.ExtractAssociatedIcon zu verwenden.

This is good CodeProject article wie Sie SHGetFileInfo verwenden.

+0

Erhalten diese APIs die dynamischen Symbole wie das Vorschau-Symbol, das für PDF-Dokumente und Bilder generiert wird? Das verknüpfte CodeProject-Projekt speichert die Bilder im Cache nach Dateierweiterung, sodass die Antwort vermutlich nein lautet. – Triynko

1

Das Problem mit der Registrierung Ansatz ist, dass Sie nicht explizit die Symbol-Index-ID erhalten. Manchmal (wenn nicht alle Male) erhalten Sie ein Symbol ResourceID, das ein Alias ​​ist, mit dem der Anwendungsentwickler den Slot des Symbols benannt hat.

Die Registrierungsmethode impliziert daher, dass alle Entwickler ResourceIDs verwenden, die mit der impliziten Symbolindex-ID übereinstimmen (die nullbasiert, absolut, deterministisch ist).

Scannen Sie den Speicherort der Registrierung, und Sie werden viele negative Zahlen, manchmal sogar Textreferenzen zu sehen - d. H. Nicht die Symbol-Index-ID. Eine implizite Methode scheint besser zu sein, da das Betriebssystem die Arbeit ausführen kann.

Testen Sie jetzt nur diese neue Methode, aber es macht Sinn und hoffentlich löst dieses Problem.

+1

Update - Zachs Link funktioniert großartig! Shell kümmert sich um die harte Arbeit und ich muss mich nicht mehr um Ressourcen/Icon IDs kümmern :) Danke Leute – OnyxxOr

1

Wenn Sie für eine bestimmte Erweiterung in einem Symbol nur daran interessiert sind, und wenn Sie nichts dagegen haben keine temporäre Datei erstellen, können Sie das Beispiel here

C# -Code angezeigt folgen:

public Icon LoadIconFromExtension(string extension) 
    { 
     string path = string.Format("dummy{0}", extension); 
     using (File.Create(path)) { } 
     Icon icon = Icon.ExtractAssociatedIcon(path); 
     File.Delete(path); 
     return icon; 
    } 
5

Nichts mehr als eine C# -Version von Stefans Antwort.

using System.Drawing; 

class Class1 
{ 
    public static void Main() 
    { 
     var filePath = @"C:\myfile.exe"; 
     var theIcon = IconFromFilePath(filePath); 

     if (theIcon != null) 
     { 
      // Save it to disk, or do whatever you want with it. 
      using (var stream = new System.IO.FileStream(@"c:\myfile.ico", System.IO.FileMode.CreateNew)) 
      { 
       theIcon.Save(stream); 
      } 
     } 
    } 

    public static Icon IconFromFilePath(string filePath) 
    { 
     var result = (Icon)null; 

     try 
     { 
      result = Icon.ExtractAssociatedIcon(filePath); 
     } 
     catch (System.Exception) 
     { 
      // swallow and return nothing. You could supply a default Icon here as well 
     } 

     return result; 
    } 
} 
4

Das funktioniert für mich in meinen Projekten, hoffe das hilft jemandem.

Es ist C# mit P/Invokes es wird bisher auf x86/x64-Systemen seit WinXP arbeiten.

(Shell.cs)

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

namespace IconExtraction 
{ 
    internal sealed class Shell : NativeMethods 
    { 
     #region OfExtension 

     ///<summary> 
     /// Get the icon of an extension 
     ///</summary> 
     ///<param name="filename">filename</param> 
     ///<param name="overlay">bool symlink overlay</param> 
     ///<returns>Icon</returns> 
     public static Icon OfExtension(string filename, bool overlay = false) 
     { 
      string filepath; 
      string[] extension = filename.Split('.'); 
      string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache"); 
      Directory.CreateDirectory(dirpath); 
      if (String.IsNullOrEmpty(filename) || extension.Length == 1) 
      { 
       filepath = Path.Combine(dirpath, "dummy_file"); 
      } 
      else 
      { 
       filepath = Path.Combine(dirpath, String.Join(".", "dummy", extension[extension.Length - 1])); 
      } 
      if (File.Exists(filepath) == false) 
      { 
       File.Create(filepath); 
      } 
      Icon icon = OfPath(filepath, true, true, overlay); 
      return icon; 
     } 
     #endregion 

     #region OfFolder 

     ///<summary> 
     /// Get the icon of an extension 
     ///</summary> 
     ///<returns>Icon</returns> 
     ///<param name="overlay">bool symlink overlay</param> 
     public static Icon OfFolder(bool overlay = false) 
     { 
      string dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache", "dummy"); 
      Directory.CreateDirectory(dirpath); 
      Icon icon = OfPath(dirpath, true, true, overlay); 
      return icon; 
     } 
     #endregion 

     #region OfPath 

     ///<summary> 
     /// Get the normal,small assigned icon of the given path 
     ///</summary> 
     ///<param name="filepath">physical path</param> 
     ///<param name="small">bool small icon</param> 
     ///<param name="checkdisk">bool fileicon</param> 
     ///<param name="overlay">bool symlink overlay</param> 
     ///<returns>Icon</returns> 
     public static Icon OfPath(string filepath, bool small = true, bool checkdisk = true, bool overlay = false) 
     { 
      Icon clone; 
      SHGFI_Flag flags; 
      SHFILEINFO shinfo = new SHFILEINFO(); 
      if (small) 
      { 
       flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_SMALLICON; 
      } 
      else 
      { 
       flags = SHGFI_Flag.SHGFI_ICON | SHGFI_Flag.SHGFI_LARGEICON; 
      } 
      if (checkdisk == false) 
      { 
       flags |= SHGFI_Flag.SHGFI_USEFILEATTRIBUTES; 
      } 
      if (overlay) 
      { 
       flags |= SHGFI_Flag.SHGFI_LINKOVERLAY; 
      } 
      if (SHGetFileInfo(filepath, 0, ref shinfo, Marshal.SizeOf(shinfo), flags) == 0) 
      { 
       throw (new FileNotFoundException()); 
      } 
      Icon tmp = Icon.FromHandle(shinfo.hIcon); 
      clone = (Icon)tmp.Clone(); 
      tmp.Dispose(); 
      if (DestroyIcon(shinfo.hIcon) != 0) 
      { 
       return clone; 
      } 
      return clone; 
     } 
     #endregion 
    } 
} 

(NativeMethods.cs)

using System; 
using System.Drawing; 
using System.Runtime.InteropServices; 

namespace IconExtraction 
{ 
    internal class NativeMethods 
    { 
     public struct SHFILEINFO 
     { 
      public IntPtr hIcon; 
      public int iIcon; 
      public uint dwAttributes; 
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
      public string szDisplayName; 
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] 
      public string szTypeName; 
     }; 

     [DllImport("user32.dll")] 
     public static extern int DestroyIcon(IntPtr hIcon); 

     [DllImport("shell32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)] 
     public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex); 

     [DllImport("Shell32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] 
     public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags); 

     [DllImport("Shell32.dll")] 
     public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags); 
    } 

    public enum SHGFI_Flag : uint 
    { 
     SHGFI_ATTR_SPECIFIED = 0x000020000, 
     SHGFI_OPENICON = 0x000000002, 
     SHGFI_USEFILEATTRIBUTES = 0x000000010, 
     SHGFI_ADDOVERLAYS = 0x000000020, 
     SHGFI_DISPLAYNAME = 0x000000200, 
     SHGFI_EXETYPE = 0x000002000, 
     SHGFI_ICON = 0x000000100, 
     SHGFI_ICONLOCATION = 0x000001000, 
     SHGFI_LARGEICON = 0x000000000, 
     SHGFI_SMALLICON = 0x000000001, 
     SHGFI_SHELLICONSIZE = 0x000000004, 
     SHGFI_LINKOVERLAY = 0x000008000, 
     SHGFI_SYSICONINDEX = 0x000004000, 
     SHGFI_TYPENAME = 0x000000400 
    } 
}