Obtenir l’icône de fichier utilisée par Shell

Dans .Net (C # ou VB: m’en fiche), étant donné une chaîne de chemin de fichier, une structure FileInfo ou une structure FileSystemInfo pour un fichier existant, comment puis-je déterminer la ou les icons utilisées par le shell (explorateur) pour cela? fichier?

Je ne prévois pas actuellement de l’utiliser pour quelque chose, mais je me suis demandé comment le faire lorsque je regardais cette question et j’ai pensé qu’il serait utile de l’archiver ici sur SO.

Imports System.Drawing Module Module1 Sub Main() Dim filePath As Ssortingng = "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 Ssortingng) 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 

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 une signature P / Invoke ici:

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

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 tel que “\\ ComputerName \ SharedFolder \”) alors que Icon.ExtractAssociatedIcon ne le peut pas. Si vous avez besoin ou peut-être besoin d’utiliser des chemins UNC, il serait préférable d’utiliser SHGetFileInfo au lieu de Icon.ExtractAssociatedIcon.

C’est un bon article de CodeProject sur l’utilisation de SHGetFileInfo.

Rien de 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(ssortingng 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; } } 

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

C’est C # avec P / Invokes qui fonctionnera jusqu’ici 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 /// /// Get the icon of an extension /// ///filename ///bool symlink overlay ///Icon public static Icon OfExtension(ssortingng filename, bool overlay = false) { ssortingng filepath; ssortingng[] extension = filename.Split('.'); ssortingng dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache"); Directory.CreateDirectory(dirpath); if (Ssortingng.IsNullOrEmpty(filename) || extension.Length == 1) { filepath = Path.Combine(dirpath, "dummy_file"); } else { filepath = Path.Combine(dirpath, Ssortingng.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 /// /// Get the icon of an extension /// ///Icon ///bool symlink overlay public static Icon OfFolder(bool overlay = false) { ssortingng dirpath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "cache", "dummy"); Directory.CreateDirectory(dirpath); Icon icon = OfPath(dirpath, true, true, overlay); return icon; } #endregion #region OfPath /// /// Get the normal,small assigned icon of the given path /// ///physical path ///bool small icon ///bool fileicon ///bool symlink overlay ///Icon public static Icon OfPath(ssortingng 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 dwAtsortingbutes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public ssortingng szDisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public ssortingng 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, ssortingng lpszExeFileName, int nIconIndex); [DllImport("Shell32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern int SHGetFileInfo(ssortingng pszPath, int dwFileAtsortingbutes, ref SHFILEINFO psfi, int cbFileInfo, SHGFI_Flag uFlags); [DllImport("Shell32.dll")] public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAtsortingbutes, 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 } } 

Le problème avec l’approche du registre est que vous n’obtenez pas explicitement l’ID d’index d’icône. Parfois (sinon tous les temps), 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 ResourceID identiques à l’ID d’index implicite (basé sur zéro, absolu, déterministe).

Analysez l’emplacement du registre et vous verrez beaucoup de nombres négatifs, parfois même des références de texte – c’est-à-dire pas l’id d’index des icons. Une méthode implicite semble préférable car elle permet au système d’exploitation de faire le travail.

Seulement tester cette nouvelle méthode maintenant, mais cela a du sens et, espérons-le, résout ce problème.

Si vous êtes uniquement intéressé 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é ici

Code C #:

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

Ce lien semble avoir des informations. Cela implique beaucoup de parcours de registre, mais cela semble faisable. Les exemples sont en C ++

  • déterminer l’extension
  • dans le registre, allez à "HKCR\.{extension}" , lisez la valeur par défaut (appelons-le filetype )
  • dans "HKCR\{filetype}\DefaultIcon" , lisez la valeur par défaut: il s’agit du chemin d’access au fichier d’icône (ou au fichier de conteneur d’icons, comme un fichier .exe avec une ressource d’icône intégrée)
  • si nécessaire, utilisez votre méthode préférée pour extraire la ressource icône du fichier mentionné

éditer / remonter des commentaires:

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