C# 如何在WPF中显示Windows文件图标?
目前,我通过调用SHGetFileInfo获得了一个本机图标。然后,我将使用以下代码将其转换为位图。位图最终以WPF形式显示 有没有更快的方法来做同样的事情C# 如何在WPF中显示Windows文件图标?,c#,wpf,icons,C#,Wpf,Icons,目前,我通过调用SHGetFileInfo获得了一个本机图标。然后,我将使用以下代码将其转换为位图。位图最终以WPF形式显示 有没有更快的方法来做同样的事情 try { using (Icon i = Icon.FromHandle(shinfo.hIcon)) { Bitmap bmp = i.ToBitmap(); MemoryStream strm = new M
try
{
using (Icon i = Icon.FromHandle(shinfo.hIcon))
{
Bitmap bmp = i.ToBitmap();
MemoryStream strm = new MemoryStream();
bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
strm.Seek(0, SeekOrigin.Begin);
bmpImage.StreamSource = strm;
bmpImage.EndInit();
return bmpImage;
}
}
finally
{
Win32.DestroyIcon(hImgLarge);
}
我相信这里有更简单(更有管理)的方法来解决这个问题。
解决方案的关键在于这里
System.Drawing.Icon formIcon = IconsInWPF.Properties.Resources.Habs;
MemoryStream stream = new MemoryStream();
formIcon.Save(stream);
this.Icon = BitmapFrame.Create(stream);
托马斯的代码可以简化得更多。以下是带有附加错误检查的完整代码:
Interop.SHGetFileInfo(path, isFile, ref pifFileInfo);
IntPtr iconHandle = pifFileInfo.hIcon;
if (IntPtr.Zero == iconHandle)
return DefaultImgSrc;
ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
iconHandle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
User32.DestroyIcon(iconHandle);
return img;
区别在于:
- 无需创建图标对象
- 确保处理iconHandle为0(IntPtr.Zero)的情况,例如返回一些预定义的ImageSource对象
- 如果win32 api DestroyIcon()来自SHGetFileInfo(),请确保使用它
- 像这样的东西怎么样:
var icon = System.Drawing.Icon.ExtractAssociatedIcon(fileName);
var bmp = icon.ToBitmap()
结合谷歌搜索,我编造了以下内容:
方法:
/*
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
*/
public static ImageSource GetIcon(string strPath, bool bSmall)
{
Interop.SHFILEINFO info = new Interop.SHFILEINFO(true);
int cbFileInfo = Marshal.SizeOf(info);
Interop.SHGFI flags;
if (bSmall)
flags = Interop.SHGFI.Icon | Interop.SHGFI.SmallIcon | Interop.SHGFI.UseFileAttributes;
else
flags = Interop.SHGFI.Icon | Interop.SHGFI.LargeIcon | Interop.SHGFI.UseFileAttributes;
Interop.SHGetFileInfo(strPath, 256, out info, (uint)cbFileInfo, flags);
IntPtr iconHandle = info.hIcon;
//if (IntPtr.Zero == iconHandle) // not needed, always return icon (blank)
// return DefaultImgSrc;
ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
iconHandle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
Interop.DestroyIcon(iconHandle);
return img;
}
和互操作类:
using System;
using System.Runtime.InteropServices;
public static class Interop
{
/// <summary>Maximal Length of unmanaged Windows-Path-strings</summary>
private const int MAX_PATH = 260;
/// <summary>Maximal Length of unmanaged Typename</summary>
private const int MAX_TYPE = 80;
[Flags]
public enum SHGFI : int
{
/// <summary>get icon</summary>
Icon = 0x000000100,
/// <summary>get display name</summary>
DisplayName = 0x000000200,
/// <summary>get type name</summary>
TypeName = 0x000000400,
/// <summary>get attributes</summary>
Attributes = 0x000000800,
/// <summary>get icon location</summary>
IconLocation = 0x000001000,
/// <summary>return exe type</summary>
ExeType = 0x000002000,
/// <summary>get system icon index</summary>
SysIconIndex = 0x000004000,
/// <summary>put a link overlay on icon</summary>
LinkOverlay = 0x000008000,
/// <summary>show icon in selected state</summary>
Selected = 0x000010000,
/// <summary>get only specified attributes</summary>
Attr_Specified = 0x000020000,
/// <summary>get large icon</summary>
LargeIcon = 0x000000000,
/// <summary>get small icon</summary>
SmallIcon = 0x000000001,
/// <summary>get open icon</summary>
OpenIcon = 0x000000002,
/// <summary>get shell size icon</summary>
ShellIconSize = 0x000000004,
/// <summary>pszPath is a pidl</summary>
PIDL = 0x000000008,
/// <summary>use passed dwFileAttribute</summary>
UseFileAttributes = 0x000000010,
/// <summary>apply the appropriate overlays</summary>
AddOverlays = 0x000000020,
/// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
OverlayIndex = 0x000000040,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEINFO
{
public SHFILEINFO(bool b)
{
hIcon = IntPtr.Zero;
iIcon = 0;
dwAttributes = 0;
szDisplayName = "";
szTypeName = "";
}
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
public string szTypeName;
};
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern int SHGetFileInfo(
string pszPath,
int dwFileAttributes,
out SHFILEINFO psfi,
uint cbfileInfo,
SHGFI uFlags);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyIcon(IntPtr hIcon);
}
使用系统;
使用System.Runtime.InteropServices;
公共静态类互操作
{
///非托管Windows路径字符串的最大长度
私有常量int MAX_PATH=260;
///非托管Typename的最大长度
私有常量int MAX_TYPE=80;
[旗帜]
公共枚举SHGFI:int
{
///获取图标
图标=0x000000100,
///获取显示名称
DisplayName=0x000000200,
///获取类型名
TypeName=0x000000400,
///获取属性
属性=0x000000800,
///获取图标位置
IconLocation=0x000001000,
///返回exe类型
ExeType=0x000002000,
///获取系统图标索引
SysIconIndex=0x000004000,
///在图标上放置一个链接覆盖
LinkOverlay=0x00008000,
///在选定状态下显示图标
所选=0x000010000,
///仅获取指定的属性
指定的属性=0x000020000,
///获取大图标
LargeIcon=0x000000000,
///获取小图标
SmallIcon=0x000000001,
///打开图标
OpenIcon=0x000000002,
///获取外壳大小图标
ShellIconSize=0x000000004,
///pszPath是一个pidl
PIDL=0x000000008,
///使用传递的dwFileAttribute
UseFileAttributes=0x000000010,
///应用适当的覆盖层
AddOverlays=0x000000020,
///获取iIcon上8位的覆盖索引
OverlayIndex=0x000000040,
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
公共结构SHFILEINFO
{
公共SHFILEINFO(布尔b)
{
hIcon=IntPtr.Zero;
iIcon=0;
dwAttributes=0;
szDisplayName=“”;
szTypeName=“”;
}
公共IntPtr hIcon;
公共国际会议;
公共单位属性;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=MAX\u PATH)]
公共字符串名称;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=MAX\u TYPE)]
公共字符串类型名;
};
[DllImport(“shell32.dll”,CharSet=CharSet.Auto)]
公共静态外部int SHGetFileInfo(
字符串pszPath,
int dwFileAttributes,
输出SHFILEINFO psfi,
uint cbfileInfo,
SHGFI uFlags);
[DllImport(“user32.dll”,SetLastError=true)]
公共静态外部布尔销毁图标(IntPtr hIcon);
}
很明显,您的问题还不够复杂;)@Slomojo使用System.Drawing and Bitmap=Icon.ExtractAssociatedIcon(文件名)。ToBitmap()也可以工作…ToBitmap()丢失alpha通道这只提取分辨率为32x32的图标。您可以直接将图标转换为图像源,而不是使用
Icon.ToBitmap(),使用图标。句柄
属性和Thomas或Krysztof答案。或者您可以提供互操作代码吗?我在将您的代码与Windows API中SHGetFileInfo的函数签名匹配时遇到问题。我发现的所有其他解决方案都使用System.Drawing,它似乎与WPF 100%不兼容,所以为什么还要麻烦使用它呢。这看起来最直截了当。如果我能让它工作。Interop类和其他组合在下面(太长了,无法评论)复制/粘贴解决方案+1.只是一个小小的注释:您应该坚持使用“BitmapSource”基类而不是“ImageSource”,因为一旦升级,就很难回溯到基类。否则,答案是完美的。谢谢,很好用。一个改进:由于加载多个文件的图标可能需要一段时间,因此您可能希望在工作线程中执行此操作。要在UI中使用这样的图像,必须将其冻结:img.Freeze()代码>它无论如何都不会改变。很好的解决方案。我扩展了它,这样它也支持目录。当我想要检索文件夹图标时,我会传递FILE\u ATTRIBUTE\u DIRECTORY
(0x10),否则传递FILE\u ATTRIBUTE\u NORMAL
(0x80),而不是将幻数256传递给SHGetFileInfo。我将这两个值作为常量添加到Interop类中。已使用和中的信息。请记住在使用资源后处置它们。在这个场景中,我认为您的流没有关闭。
using System;
using System.Runtime.InteropServices;
public static class Interop
{
/// <summary>Maximal Length of unmanaged Windows-Path-strings</summary>
private const int MAX_PATH = 260;
/// <summary>Maximal Length of unmanaged Typename</summary>
private const int MAX_TYPE = 80;
[Flags]
public enum SHGFI : int
{
/// <summary>get icon</summary>
Icon = 0x000000100,
/// <summary>get display name</summary>
DisplayName = 0x000000200,
/// <summary>get type name</summary>
TypeName = 0x000000400,
/// <summary>get attributes</summary>
Attributes = 0x000000800,
/// <summary>get icon location</summary>
IconLocation = 0x000001000,
/// <summary>return exe type</summary>
ExeType = 0x000002000,
/// <summary>get system icon index</summary>
SysIconIndex = 0x000004000,
/// <summary>put a link overlay on icon</summary>
LinkOverlay = 0x000008000,
/// <summary>show icon in selected state</summary>
Selected = 0x000010000,
/// <summary>get only specified attributes</summary>
Attr_Specified = 0x000020000,
/// <summary>get large icon</summary>
LargeIcon = 0x000000000,
/// <summary>get small icon</summary>
SmallIcon = 0x000000001,
/// <summary>get open icon</summary>
OpenIcon = 0x000000002,
/// <summary>get shell size icon</summary>
ShellIconSize = 0x000000004,
/// <summary>pszPath is a pidl</summary>
PIDL = 0x000000008,
/// <summary>use passed dwFileAttribute</summary>
UseFileAttributes = 0x000000010,
/// <summary>apply the appropriate overlays</summary>
AddOverlays = 0x000000020,
/// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
OverlayIndex = 0x000000040,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEINFO
{
public SHFILEINFO(bool b)
{
hIcon = IntPtr.Zero;
iIcon = 0;
dwAttributes = 0;
szDisplayName = "";
szTypeName = "";
}
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
public string szTypeName;
};
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern int SHGetFileInfo(
string pszPath,
int dwFileAttributes,
out SHFILEINFO psfi,
uint cbfileInfo,
SHGFI uFlags);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyIcon(IntPtr hIcon);
}