c#-获取Sh使用的文件图标

在.Net(C#或VB:不在乎)中,给定文件路径字符串,FileInfo结构或FileSystemInfo结构用于实际的现有文件,我如何确定外壳程序(浏览器)为此使用的图标 文件?

我目前不打算将其用于任何用途,但是当我看着这个问题时,我对如何做到这一点感到好奇,并且我认为将其存档在SO上将很有用。

Joel Coehoorn asked 2020-06-29T20:06:25Z
9个解决方案
55 votes
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
Stefan answered 2020-06-29T20:06:29Z
16 votes

请忽略所有告诉您使用注册表的人! 注册表不是API。 您想要的API是带有SHGFI_ICON的SHGetFileInfo。 您可以在此处获得P / Invoke签名:

[HTTP://呜呜呜.P invoke.net/default.aspx/shell32.sh get file info]

answered 2020-06-29T20:06:53Z
15 votes

您应该使用SHGetFileInfo。

在大多数情况下,Icon.ExtractAssociatedIcon的工作原理与SHGetFileInfo一样,但是SHGetFileInfo可以使用UNC路径(例如“ \\ ComputerName \ SharedFolder \”之类的网络路径),而Icon.ExtractAssociatedIcon则不能。 如果需要或可能需要使用UNC路径,则最好使用SHGetFileInfo而不是Icon.ExtractAssociatedIcon。

这是有关如何使用SHGetFileInfo的优秀CodeProject文章。

Zach Johnson answered 2020-06-29T20:07:23Z
7 votes

仅仅是Stefan答案的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;
    }
}
damix911 answered 2020-06-29T20:07:42Z
4 votes

这对我的项目很有用,希望对您有所帮助。

它是带有P / Invokes的C#,自WinXP起至今,它都可以在x86 / x64系统上运行。

(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
    }
}
k1ll3r8e answered 2020-06-29T20:08:15Z
1 votes

注册表方法的问题是您没有显式获取图标索引ID。 有时(如果不是全部时间),您会得到一个图标ResourceID,该ID是应用程序开发人员用来命名图标插槽的别名。

因此,该注册表方法意味着所有开发人员都使用与隐式图标索引ID(基于零,绝对,确定性)相同的ResourceID。

扫描注册表位置,您会看到很多负数,有时甚至是文本引用-即不是图标索引ID。 隐式方法似乎更好,因为它可以让OS完成工作。

现在只测试这种新方法,但这是有意义的,并有望解决此问题。

OnyxxOr answered 2020-06-29T20:08:49Z
1 votes

如果您只对特定扩展名的图标感兴趣,并且不介意创建临时文件,则可以按照此处显示的示例进行操作

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;
    }
Default answered 2020-06-29T20:09:14Z
0 votes

该链接似乎有一些信息。 它涉及很多注册表遍历,但似乎可行。 示例在C ++中

Jason Punyon answered 2020-06-29T20:09:34Z
0 votes
  • 确定扩展名
  • 在注册表中,转到"foo.exe,3",读取默认值(将其命名为filetype
  • "foo.exe,3"中,读取默认值:这是图标文件(或图标容器文件,例如带有嵌入式图标资源的.exe)的路径
  • 如果需要,使用首选的方法从提到的文件中提取图标资源

编辑/从评论中移出:

如果图标在容器文件中(这是很常见的),则路径后会有一个计数器,如下所示:"foo.exe,3"。这意味着它是可用图标的图标编号4(索引从零开始)。 值“,0”是隐式的(并且是可选的)。 如果计数器为0或丢失,则外壳将使用第一个可用图标。

Tomalak answered 2020-06-29T20:10:16Z
translate from https://stackoverflow.com:/questions/462270/get-file-icon-used-by-shell