C# 获取Shell使用的文件图标
在.Net(C#或VB:不在乎)中,给定一个实际现有文件的文件路径字符串、FileInfo结构或FileSystemInfo结构,如何确定shell(资源管理器)为该文件使用的图标 我目前不打算用它做任何事情,但当我看到它的时候,我对如何做感到好奇,我认为在这里存档会很有用。链接似乎有一些信息。它涉及大量的注册表遍历,但似乎是可行的。示例使用C++C# 获取Shell使用的文件图标,c#,.net,vb.net,winforms,shell-icons,C#,.net,Vb.net,Winforms,Shell Icons,在.Net(C#或VB:不在乎)中,给定一个实际现有文件的文件路径字符串、FileInfo结构或FileSystemInfo结构,如何确定shell(资源管理器)为该文件使用的图标 我目前不打算用它做任何事情,但当我看到它的时候,我对如何做感到好奇,我认为在这里存档会很有用。链接似乎有一些信息。它涉及大量的注册表遍历,但似乎是可行的。示例使用C++ Imports System.Drawing Module Module1 Sub Main() Dim file
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
“HKCR\.{extension}”
,读取默认值(我们称之为文件类型
)如果图标位于容器文件中(这是很常见的),则路径后面会有一个计数器,如下所示:
“foo.exe,3”
。这意味着它是可用图标的图标编号4(索引以零为基础)。“0”的值是隐式的(可选)。如果计数器为0或丢失,shell将使用第一个可用图标。请忽略所有告诉您使用注册表的人!注册表不是API。您需要的API是带有SHGFI_图标的SHGetFileInfo。您可以在此处获得P/Invoke签名:
您应该使用SHGetFileInfo Icon.ExtractAssociatedIcon在大多数情况下与SHGetFileInfo一样工作,但SHGetFileInfo可以使用UNC路径(例如“\\ComputerName\SharedFolder\”之类的网络路径),而Icon.ExtractAssociatedIcon不能。如果您需要或可能需要使用UNC路径,最好使用SHGetFileInfo而不是Icon.ExtractAssociatedIcon
关于如何使用SHGetFileInfo。注册表方法的问题是,您没有显式获取图标索引id。有时(如果不是所有时候),您会获得一个图标资源id,它是应用程序开发人员用来命名图标插槽的别名 因此,注册表方法意味着所有开发人员都使用与隐式图标索引id相同的ResourceID(基于零的、绝对的、确定性的) 扫描注册表位置,你会看到很多负数,有时甚至是文本引用-即不是图标索引id。隐式方法似乎更好,因为它可以让操作系统完成工作
现在只测试这个新方法,但它是有意义的,有望解决这个问题。如果您只对特定扩展名的图标感兴趣,并且不介意创建一个临时文件,那么可以按照显示的示例进行操作 C#代码: 只不过是斯特凡答案的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;
}
}
这在我的项目中对我有用,希望这对别人有帮助 它是带有p/Invokes的C#,自WinXP以来,到目前为止,它将在x86/x64系统上运行 (Shell.cs)
对于.exes、.dll或其他包含图标的文件来说,这很好。但是,对于文本文件或其他简单文件,图标可能会根据安装的程序或用户更改的设置而有所不同。它应该适用于所有具有关联图标的文件,而不必具有我所知道的关联程序。测试表明,这是可行的。我不清楚他最初的解释——我以为它只是在文件本身中寻找图标资源,但令人高兴的是事实并非如此。太棒了!如何获取文件夹的图标?如果要对WPF执行相同的操作,可以使用System.Drawing.icon的Handle属性为图像创建位图源:Image.Source=System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(result.Handle,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());请注意,ExtractAssociatedIcon始终返回32x32像素版本的图标。如果是包含多个图标的图标容器文件,您如何知道使用哪个图标?路径后有一个计数器,如“foo.exe,3”。这意味着它是可用图标的第4号图标(索引为零)。“0”的值是隐式的,因此是可选的。如果缺少,shell将使用第一个可用图标。注册表不是API!还有其他指定图标的方法,这种方法是错误的。请为此使用SHGetFileInfo API。@timbagas:“此方法将是错误的”。。。除了“不使用API”之外,还有什么别的错误呢?因为我们要的是C#或VB,Stefan的答案要简单得多。如果有人想在unity3d中获得图标,那么这个方法就行了。我尝试了
System.Drawing.Icon.ExtractAssociatedIcon
&shell32.dll ExtractAssociatedIcon。虽然第一种方法给了我错误的图标,但第二种方法有效,但图标并不总是正确的。最后,我无意中发现了这个答案,它完全符合我的预期。更新-扎克的链接效果很好!Shell负责这项艰巨的工作,我不必再担心资源/图标ID:)谢谢Guysd这些API是否获得了动态图标,如为PDF文档和图像生成的预览图标?链接的CodeProject项目通过文件扩展名缓存图像,因此答案似乎是否定的。我想从命令行中找到一种方法来实现这一点,所以我将这个答案转换为在BAT脚本中自编译和执行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;
}
}
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
}
}
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
}
}