How do I display a Windows file icon in WPF?
Currently I'm getting a native icon by calling SHGetFileInfo. Then, I'm converting it to a bitmap using the following code. The Bitmap eventually gets displayed in the WPF form.
Is there a faster way to do the same thing?
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.EndI开发者_JAVA技巧nit();
return bmpImage;
}
}
finally
{
Win32.DestroyIcon(hImgLarge);
}
How about something like:
var icon = System.Drawing.Icon.ExtractAssociatedIcon(fileName);
var bmp = icon.ToBitmap()
using System.Windows.Interop;
...
ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
shinfo.hIcon,
new Int32Rect(0,0,i.Width, i.Height),
BitmapSizeOptions.FromEmptyOptions());
Combining Krzysztof Kowalczyk answer with some googling, i made up this:
Method:
/*
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;
}
and Interop class:
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);
}
source
Thomas's code could be simplified even more. Here's the full code with additional error checking:
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;
The difference is:
- no need to create Icon object
- make sure to handle a case where iconHandle is 0 (IntPtr.Zero) by e.g. returning some pre-defined ImageSource object
- make sure to use win32 api DestroyIcon() if it comes from SHGetFileInfo()
I belive there's simpler (more managed) way of solving this hilighted here. http://www.pchenry.com/Home/tabid/36/EntryID/193/Default.aspx
The crux is of the solution is here.
System.Drawing.Icon formIcon = IconsInWPF.Properties.Resources.Habs;
MemoryStream stream = new MemoryStream();
formIcon.Save(stream);
this.Icon = BitmapFrame.Create(stream);
精彩评论