Получить значок файла, используемый Shell - PullRequest
44 голосов
/ 20 января 2009

В .Net (C # или VB: все равно), учитывая строку пути к файлу, структуру FileInfo или структуру FileSystemInfo для реального существующего файла, как я могу определить пиктограммы, используемые оболочкой (проводником) ) для этого файла?

В настоящее время я не планирую использовать это для чего-либо, но мне стало интересно, как это сделать, глядя на этот вопрос , и я подумал, что было бы полезно заархивировать его здесь на SO.

Ответы [ 9 ]

53 голосов
/ 20 января 2009
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
16 голосов
/ 20 января 2009

Пожалуйста, игнорируйте всех, кто говорит вам использовать реестр! Реестр НЕ является API. Нужный API - это SHGetFileInfo с SHGFI_ICON. Вы можете получить подпись P / Invoke здесь:

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

15 голосов
/ 05 мая 2009

Вы должны использовать SHGetFileInfo.

Icon.ExtractAssociatedIcon в большинстве случаев работает так же хорошо, как и SHGetFileInfo, но SHGetFileInfo может работать с UNC-путями (например, сетевой путь типа "\\ ComputerName \ SharedFolder \"), а Icon.ExtractAssociatedIcon не может. Если вам нужно или может понадобиться использовать UNC-пути, лучше использовать SHGetFileInfo вместо Icon.ExtractAssociatedIcon.

Это хорошая статья CodeProject о том, как использовать SHGetFileInfo.

6 голосов
/ 18 октября 2013

Не более чем версия ответа Стефана на C #.

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 голосов
/ 10 июня 2014

Это работает для меня в моих проектах, надеюсь, это кому-нибудь поможет.

Это C # с P / Вызывает, что он будет работать до сих пор на системах x86 / x64 начиная с 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
    }
}
1 голос
/ 29 июня 2012

Если вас интересует только значок для определенного расширения, и если вы не возражаете против создания временного файла, вы можете следовать приведенному примеру здесь

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;
    }
1 голос
/ 27 июля 2011

Проблема с подходом реестра заключается в том, что вы явно не получаете идентификатор индекса иконки. Иногда (если не всегда) вы получаете значок ResourceID, который является псевдонимом, который разработчик приложения использовал для обозначения слота значка.

Таким образом, метод реестра подразумевает, что все разработчики используют ResourceID, которые совпадают с неявным идентификатором индекса иконки (который является нулевым, абсолютным, детерминированным).

Сканирование местоположения реестра, и вы увидите много отрицательных чисел, иногда даже текстовые ссылки - т.е. не идентификатор индекса значка. Неявный метод кажется лучше, так как он позволяет ОС делать всю работу.

Только сейчас тестирую этот новый метод, но он имеет смысл и, надеюсь, решит эту проблему.

0 голосов
/ 20 января 2009
  • определить расширение
  • в реестре, перейдите к "HKCR\.{extension}", прочитайте значение по умолчанию (назовем его filetype)
  • в "HKCR\{filetype}\DefaultIcon", прочитайте значение по умолчанию: это путь к файлу значка (или файлу контейнера значка, например .exe со встроенным ресурсом значка)
  • при необходимости используйте предпочитаемый метод извлечения ресурса значка из упомянутого файла

редактировать / перемещать вверх от комментариев:

Если значок находится в файле контейнера (это довольно часто), после пути будет счетчик, например: "foo.exe,3". Это означает, что это значок № 4 (индекс начинается с нуля) из доступных значков. Значение «, 0» неявно (и необязательно). Если счетчик равен 0 или отсутствует, оболочкой будет использоваться значок «Доступен первый».

0 голосов
/ 20 января 2009

Эта ссылка содержит некоторую информацию. Это включает в себя много обходов реестра, но это кажется выполнимым. Примеры в C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...