C# 获取给定扩展名的图标
我知道我可以使用C# 获取给定扩展名的图标,c#,C#,我知道我可以使用 using (System.Drawing.Icon sysicon = System.Drawing.Icon.ExtractAssociatedIcon(filePath)) { icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( sysicon.Handle, System.Windows.Int32Rect.Empty, System
using (System.Drawing.Icon sysicon = System.Drawing.Icon.ExtractAssociatedIcon(filePath))
{
icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
sysicon.Handle,
System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
但是,如果没有文件,如何获取给定扩展名的图标?使用Paul Ingles的CodeProject文章中的
GetFileIcon
方法,并将.ext
作为名称
参数传递
GetFileIcon
方法是本机的包装器,复制到此处以供说明:
public static System.Drawing.Icon GetFileIcon(string name, IconSize size,
bool linkOverlay)
{
Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;
if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY;
/* Check the size specified for return. */
if (IconSize.Small == size)
{
flags += Shell32.SHGFI_SMALLICON ; // include the small icon flag
}
else
{
flags += Shell32.SHGFI_LARGEICON ; // include the large icon flag
}
Shell32.SHGetFileInfo( name,
Shell32.FILE_ATTRIBUTE_NORMAL,
ref shfi,
(uint) System.Runtime.InteropServices.Marshal.SizeOf(shfi),
flags );
// Copy (clone) the returned icon to a new object, thus allowing us
// to call DestroyIcon immediately
System.Drawing.Icon icon = (System.Drawing.Icon)
System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon( shfi.hIcon ); // Cleanup
return icon;
}
以下代码也是基于,但:
- 可与WPF一起使用(
而不是ImageSource
)图标
- 具有简单的缓存
- 删除了所有与目录相关的内容(我的目录中只有文件) (案例)
- 使用R#tips进行重构,并使用单个类简单API进行包装
windows7
和windowsxpsp3
上测试过它,它可以像预期的那样使用任何字符串作为文件名
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
/// <summary>
/// Internals are mostly from here: http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
/// Caches all results.
/// </summary>
public static class IconManager
{
private static readonly Dictionary<string, ImageSource> _smallIconCache = new Dictionary<string, ImageSource>();
private static readonly Dictionary<string, ImageSource> _largeIconCache = new Dictionary<string, ImageSource>();
/// <summary>
/// Get an icon for a given filename
/// </summary>
/// <param name="fileName">any filename</param>
/// <param name="large">16x16 or 32x32 icon</param>
/// <returns>null if path is null, otherwise - an icon</returns>
public static ImageSource FindIconForFilename(string fileName, bool large)
{
var extension = Path.GetExtension(fileName);
if (extension == null)
return null;
var cache = large ? _largeIconCache : _smallIconCache;
ImageSource icon;
if (cache.TryGetValue(extension, out icon))
return icon;
icon = IconReader.GetFileIcon(fileName, large ? IconReader.IconSize.Large : IconReader.IconSize.Small, false).ToImageSource();
cache.Add(extension, icon);
return icon;
}
/// <summary>
/// http://stackoverflow.com/a/6580799/1943849
/// </summary>
static ImageSource ToImageSource(this Icon icon)
{
var imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
/// <summary>
/// Provides static methods to read system icons for both folders and files.
/// </summary>
/// <example>
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
/// </example>
static class IconReader
{
/// <summary>
/// Options to specify the size of icons to return.
/// </summary>
public enum IconSize
{
/// <summary>
/// Specify large icon - 32 pixels by 32 pixels.
/// </summary>
Large = 0,
/// <summary>
/// Specify small icon - 16 pixels by 16 pixels.
/// </summary>
Small = 1
}
/// <summary>
/// Returns an icon for a given file - indicated by the name parameter.
/// </summary>
/// <param name="name">Pathname for file.</param>
/// <param name="size">Large or small</param>
/// <param name="linkOverlay">Whether to include the link icon</param>
/// <returns>System.Drawing.Icon</returns>
public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
{
var shfi = new Shell32.Shfileinfo();
var flags = Shell32.ShgfiIcon | Shell32.ShgfiUsefileattributes;
if (linkOverlay) flags += Shell32.ShgfiLinkoverlay;
/* Check the size specified for return. */
if (IconSize.Small == size)
flags += Shell32.ShgfiSmallicon;
else
flags += Shell32.ShgfiLargeicon;
Shell32.SHGetFileInfo(name,
Shell32.FileAttributeNormal,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
User32.DestroyIcon(shfi.hIcon); // Cleanup
return icon;
}
}
/// <summary>
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
/// courtesy of MSDN Cold Rooster Consulting case study.
/// </summary>
static class Shell32
{
private const int MaxPath = 256;
[StructLayout(LayoutKind.Sequential)]
public struct Shfileinfo
{
private const int Namesize = 80;
public readonly IntPtr hIcon;
private readonly int iIcon;
private readonly uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
private readonly string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Namesize)]
private readonly string szTypeName;
};
public const uint ShgfiIcon = 0x000000100; // get icon
public const uint ShgfiLinkoverlay = 0x000008000; // put a link overlay on icon
public const uint ShgfiLargeicon = 0x000000000; // get large icon
public const uint ShgfiSmallicon = 0x000000001; // get small icon
public const uint ShgfiUsefileattributes = 0x000000010; // use passed dwFileAttribute
public const uint FileAttributeNormal = 0x00000080;
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
ref Shfileinfo psfi,
uint cbFileInfo,
uint uFlags
);
}
/// <summary>
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
/// </summary>
static class User32
{
/// <summary>
/// Provides access to function required to delete handle. This method is used internally
/// and is not required to be called separately.
/// </summary>
/// <param name="hIcon">Pointer to icon handle.</param>
/// <returns>N/A</returns>
[DllImport("User32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
}
}
可以做得简单得多:
System.Drawing.Icon.ExtractAssociatedIcon("<fullPath>");
System.Drawing.Icon.ExtractAssociatedIcon(“”);
重要注意事项:如果文件不存在,因此不值得添加验证,则会引发异常。您的意思是使用windows分配给新文件的默认图标吗?因为在这种情况下,它取决于文件扩展名。请详细说明您想要什么。这可能不是最优雅的解决方案(实际上是noob解决方案),但我要做的是创建一个具有我想要的扩展名的临时空文件,而不是使用上面显示的方法获取该文件的图标,然后将其删除。这样你就不必访问注册表,也不必进入Win32之类的东西。这能得到巨型图标吗?@Nighthawk441我不知道什么是巨型图标(大图标?)。您最好自己试试。请注意:不,SHGetFileInfo最多只能返回32x32像素。理想情况下,这应该将StringComparer.OrdinalIgnoreCase传递给图像构造函数,因此,文件扩展名比较不区分大小写。抛出一个System.ArgumentException:“传递给Icon的Win32句柄无效或类型错误。”
。不可靠。工作频率高达32x32像素。。。不适合。。。好了,现在还有什么需要说明的,比如文件必须存在,但它不一定是有效的-Icon.ExtractAssociatedIcon(@“c:\temp\this\u实际上是一个文本文件.xls”)
将返回正确的Excel图标,即使该文件只是一个文本文件。另外需要注意的是,尽管指示fullPath
是UNC路径,但在我的测试中,即使file.Exists()存在,调用也会引发位于网络共享上的文件
给了他们a-ok。只是想补充一点,这也会修改文件的LastAccessTime;/我在寻找一种方法来提取一个图标,但不修改访问权限time@stuartdWindows也是如此……)OP要求图标按扩展名,而不是按实际的二进制文件类型-我想,这根本不可能:)在我的用例中,我手头只有扩展名本身,所以我创建了一个tempfile并用扩展名再次保存它(我承认如果有很多条目要迭代,这将是一个地狱过载…),调用ExtractAssociatedIcon后,我无法直接调用IO.File.Delete(),因为该文件仍在使用中。因此,请注意这种情况,如果使用这种方式,需要进行一些额外的清理。:)