C# 获取 Shell 使用的文件图标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/462270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get File Icon used by Shell
提问by Joel Coehoorn
In .Net (C# or VB: don't care), given a file path string, FileInfo struct, or FileSystemInfo struct for a real existing file, how can I determine the icon(s) used by the shell (explorer) for that file?
在 .Net(C# 或 VB:不关心)中,给定一个真实现有文件的文件路径字符串、FileInfo 结构或 FileSystemInfo 结构,我如何确定外壳(资源管理器)为此使用的图标文件?
I'm not currently planning to use this for anything, but I became curious about how to do it when looking at this questionand I thought it would be useful to have archived here on SO.
我目前不打算将它用于任何事情,但是在查看这个问题时我对如何去做感到好奇,我认为在 SO 上存档会很有用。
采纳答案by Stefan
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
回答by Jason Punyon
回答by Tomalak
- determine extension
- in registry, go to
"HKCR\.{extension}"
, read the default value (let's call itfiletype
) - in
"HKCR\{filetype}\DefaultIcon"
, read the default value: this is the path to the icon file (or icon container file, like an .exe with an embedded icon resource) - if needed, use your preferred method of extracting the icon resource out of the mentioned file
- 确定延期
- 在注册表中,转到
"HKCR\.{extension}"
,读取默认值(我们称之为filetype
) - 在 中
"HKCR\{filetype}\DefaultIcon"
,读取默认值:这是图标文件(或图标容器文件,如带有嵌入图标资源的 .exe)的路径 - 如果需要,请使用您喜欢的方法从提到的文件中提取图标资源
edit/moved up from the comments:
从评论中编辑/上移:
If the icon is in a container file (this is quite common), there will be a counter after the path, like this: "foo.exe,3"
. This means it is icon number 4 (the index is zero-based) of the available icons. A value of ",0" is implicit (and optional). If the counter is 0 or missing, the fist available icon will be used by the shell.
如果图标在容器文件中(这很常见),路径后面会有一个计数器,如下所示:"foo.exe,3"
. 这意味着它是可用图标的第 4 个图标(索引从零开始)。值“,0”是隐式的(并且是可选的)。如果计数器为 0 或缺失,shell 将使用第一个可用图标。
回答by Tomalak
Please ignore everyone telling you to use the registry! The registry is NOT AN API. The API you want is SHGetFileInfo with SHGFI_ICON. You can get a P/Invoke signature here:
请忽略所有告诉您使用注册表的人!注册表不是 API。您想要的 API 是带有 SHGFI_ICON 的 SHGetFileInfo。您可以在此处获得 P/Invoke 签名:
回答by Zach Johnson
You should use SHGetFileInfo.
您应该使用 SHGetFileInfo。
Icon.ExtractAssociatedIcon works just as well as SHGetFileInfo in most cases, but SHGetFileInfo can work with UNC paths (e.g. a network path like "\\ComputerName\SharedFolder\") while Icon.ExtractAssociatedIcon cannot. If you need or might need to use UNC paths, it would be best to use SHGetFileInfo instead of Icon.ExtractAssociatedIcon.
在大多数情况下,Icon.ExtractAssociatedIcon 与 SHGetFileInfo 一样有效,但 SHGetFileInfo 可以与 UNC 路径(例如像“\\ComputerName\SharedFolder\”这样的网络路径)一起使用,而 Icon.ExtractAssociatedIcon 不能。如果您需要或可能需要使用 UNC 路径,最好使用 SHGetFileInfo 而不是 Icon.ExtractAssociatedIcon。
This is good CodeProject articleon how to use SHGetFileInfo.
这是关于如何使用 SHGetFileInfo 的优秀 CodeProject 文章。
回答by OnyxxOr
The problem with the registry approach is that you are not explicitly getting the icon index id. Sometimes (if not all times), you get an icon ResourceID which is an alias the application developer used to name the icon's slot.
注册表方法的问题在于您没有明确获取图标索引 ID。有时(如果不是所有时间),您会得到一个图标 ResourceID,它是应用程序开发人员用来命名图标插槽的别名。
The registry method therefore implies that all developers use ResourceIDs which are the same as the implicit icon index id (which is zero based, absolute, deterministic).
因此,注册表方法意味着所有开发人员都使用与隐式图标索引 ID 相同的 ResourceID(它是基于零的、绝对的、确定性的)。
Scan the registry location and you will see lots of negative numbers, sometimes even text references - i.e. not the icon index id. An implicit method seems better as it lets the OS do the work.
扫描注册表位置,你会看到很多负数,有时甚至是文本引用——即不是图标索引 id。隐式方法似乎更好,因为它让操作系统完成工作。
Only testing this new method now but it makes sense and hopefully solves this problem.
现在只测试这种新方法,但它是有道理的,并有望解决这个问题。
回答by Default
If you're only interested in an icon for a specific extension and if you don't mind creating a temporary file you can follow the example displayed here
如果您只对特定扩展名的图标感兴趣,并且不介意创建临时文件,则可以按照此处显示的示例进行操作
C# 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;
}
回答by damix911
Nothing more than a C# version of Stefan's answer.
只不过是 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;
}
}
回答by k1ll3r8e
This works for me in my projects, hope this helps someone.
这在我的项目中对我有用,希望这对某人有所帮助。
It's C# with P/Invokes it will work so far on x86/x64 systems since WinXP.
它是带有 P/Invokes 的 C#,它可以在自 WinXP 以来的 x86/x64 系统上运行。
(Shell.cs)
(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)
(本机方法.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
}
}