2009-01-20 9 views
42

Dans .Net (C# ou VB: ne s'en soucie pas), étant donné une chaîne de chemin de fichier, une structure FileInfo ou une structure FileSystemInfo pour un fichier existant réel, comment puis-je déterminer les icônes utilisé par le shell (explorateur) pour ce fichier?Obtenir l'icône de fichier utilisée par Shell

Je ne prévois actuellement pas l'utiliser pour quelque chose, mais je suis devenu curieux de savoir comment le faire en regardant this question et j'ai pensé qu'il serait utile d'avoir archivé ici sur SO.

Répondre

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

C'est bien pour .EXE, .DLL ou d'autres fichiers qui contiennent des icônes. Mais qu'en est-il des fichiers texte ou d'autres fichiers simples, où l'icône peut varier en fonction du programme installé ou d'un paramètre modifié par l'utilisateur? –

+0

Il devrait fonctionner pour TOUS les fichiers qui ont une icône associée, il ne doit pas avoir un programme assoiciated ce que je sais. – Stefan

+0

Que retourne-t-il s'il n'y a pas d'icône associée? –

0

This Le lien semble contenir quelques informations. Cela implique beaucoup de traversée de registre, mais cela semble faisable. Les exemples sont en C++

0
  • déterminer l'extension
  • dans le registre, allez à "HKCR\.{extension}", lisez la valeur par défaut (nous allons l'appeler filetype)
  • en "HKCR\{filetype}\DefaultIcon", lisez la valeur par défaut: ceci est le chemin vers le fichier icône (ou l'icône fichier conteneur, comme un .exe avec une ressource icône intégrée)
  • si nécessaire, utilisez votre méthode préférée d'extraction de la ressource icône hors du fichier mentionné

modifier/déplacé vers le haut à partir des commentaires:

Si l'icône est dans un fichier de conteneur (c'est assez commun), il y aura un compteur après le chemin, comme ceci: "foo.exe,3". Cela signifie qu'il s'agit de l'icône numéro 4 (l'index est basé sur zéro) des icônes disponibles. Une valeur de ", 0" est implicite (et facultative). Si le compteur est 0 ou manquant, l'icône disponible du poing sera utilisée par le shell.

+0

S'il s'agit d'un fichier de conteneur d'icônes contenant plusieurs icônes, comment savez-vous lequel utiliser? –

+0

Il y a un compteur après le chemin, comme "foo.exe, 3". Cela signifie que c'est l'icône no. 4 (l'index est basé sur zéro) des icônes disponibles. Une valeur de ", 0" est implicite et donc facultative. S'il manque, l'icône disponible du poing sera utilisée par le shell. – Tomalak

+2

Le registre n'est pas une API! Il existe d'autres façons de spécifier des icônes, et cette méthode sera erronée. Veuillez utiliser l'API SHGetFileInfo pour cela. – Tron

15

Veuillez ignorer tout le monde vous disant d'utiliser le registre! Le registre n'est pas une API. L'API que vous souhaitez est SHGetFileInfo avec SHGFI_ICON. Vous pouvez obtenir un P/Invoke signature ici:

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

+3

Puisque nous sommes après C# ou VB, la réponse de Stefan est beaucoup plus simple. –

15

Vous devez utiliser SHGetFileInfo. Icon.ExtractAssociatedIcon fonctionne aussi bien que SHGetFileInfo dans la plupart des cas, mais SHGetFileInfo peut fonctionner avec des chemins UNC (par exemple un chemin réseau comme "\\ NomOrdinateur \ SharedFolder \"), contrairement à Icon.ExtractAssociatedIcon. Si vous avez besoin ou devez utiliser des chemins UNC, il est préférable d'utiliser SHGetFileInfo au lieu de Icon.ExtractAssociatedIcon.

This is good CodeProject article sur l'utilisation de SHGetFileInfo.

+0

Est-ce que ces API obtiennent les icônes dynamiques telles que l'icône de prévisualisation générée pour les documents PDF et les images? Le projet CodeProject lié met en cache les images par extension de fichier, il semble donc que la réponse est non. – Triynko

1

Le problème avec l'approche de registre est que vous n'obtenez pas explicitement l'ID d'index d'icône. Parfois (si ce n'est pas toujours), vous obtenez une icône ResourceID qui est un alias utilisé par le développeur de l'application pour nommer l'emplacement de l'icône.

La méthode de registre implique donc que tous les développeurs utilisent des ID de ressource qui sont identiques à l'ID d'index d'icône implicite (qui est basé sur zéro, absolu, déterministe). Scannez l'emplacement du registre et vous verrez beaucoup de nombres négatifs, parfois même des références textuelles, c'est-à-dire pas l'identifiant d'index d'icône. Une méthode implicite semble préférable car elle permet au système d'exploitation de faire le travail. Nous ne testerons cette nouvelle méthode que maintenant, mais cela a du sens et nous espérons résoudre ce problème.

+1

Mise à jour - Le lien de Zach fonctionne très bien! Shell s'occupe du dur labeur et je n'ai plus à m'inquiéter des IDs Ressource/Icon :) Merci les gars – OnyxxOr

1

Si vous n'êtes intéressé que par une icône pour une extension spécifique et si cela ne vous dérange pas de créer un fichier temporaire, vous pouvez suivre l'exemple affiché here

code C#:

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

Rien plus qu'une version C# de la réponse de Stefan.

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

Cela fonctionne pour moi dans mes projets, j'espère que cela aidera quelqu'un.

C'est C# avec P/Invoke cela fonctionnera jusqu'à présent sur les systèmes x86/x64 depuis WinXP.

(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 
    } 
} 
Questions connexes