C#/ WPF:获取shell使用的图标

我正在尝试开发一个应用程序,它可以显示目录的内容,如Windows资源管理器(带有文件名和图标)。 我目前正在使用此代码:

public class IconManager { public static ImageSource GetIcon(string path, bool smallIcon, bool isDirectory) { uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; if (smallIcon) flags |= SHGFI_SMALLICON; uint attributes = FILE_ATTRIBUTE_NORMAL; if (isDirectory) attributes |= FILE_ATTRIBUTE_DIRECTORY; SHFILEINFO shfi; if (0 != SHGetFileInfo(path, attributes, out shfi, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), flags)) { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(shfi.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } return null; } [StructLayout(LayoutKind.Sequential)] private 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("shell32")] private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags); private const uint FILE_ATTRIBUTE_READONLY = 0x00000001; private const uint FILE_ATTRIBUTE_HIDDEN = 0x00000002; private const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004; private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; private const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020; private const uint FILE_ATTRIBUTE_DEVICE = 0x00000040; private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; private const uint FILE_ATTRIBUTE_TEMPORARY = 0x00000100; private const uint FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200; private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400; private const uint FILE_ATTRIBUTE_COMPRESSED = 0x00000800; private const uint FILE_ATTRIBUTE_OFFLINE = 0x00001000; private const uint FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000; private const uint FILE_ATTRIBUTE_ENCRYPTED = 0x00004000; private const uint FILE_ATTRIBUTE_VIRTUAL = 0x00010000; private const uint SHGFI_ICON = 0x000000100; private const uint SHGFI_DISPLAYNAME = 0x000000200; private const uint SHGFI_TYPENAME = 0x000000400; private const uint SHGFI_ATTRIBUTES = 0x000000800; private const uint SHGFI_ICONLOCATION = 0x000001000; private const uint SHGFI_EXETYPE = 0x000002000; private const uint SHGFI_SYSICONINDEX = 0x000004000; private const uint SHGFI_LINKOVERLAY = 0x000008000; private const uint SHGFI_SELECTED = 0x000010000; private const uint SHGFI_ATTR_SPECIFIED = 0x000020000; private const uint SHGFI_LARGEICON = 0x000000000; private const uint SHGFI_SMALLICON = 0x000000001; private const uint SHGFI_OPENICON = 0x000000002; private const uint SHGFI_SHELLICONSIZE = 0x000000004; private const uint SHGFI_PIDL = 0x000000008; private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; } 

我使用此代码来获取带有图标的文件和目录:

 foreach (string d in Directory.GetDirectories(Path)) { string name = ""; foreach (string p in d.Split('\\')) name = p; ImageSource icon = IconManager.GetIcon(d + "\\", false, true); colDesktopItems.Add(new DesktopItem() { ItemName = name, ItemPath = d }); } foreach (string f in Directory.GetFiles(Path)) { if (File.GetAttributes(f) != FileAttributes.Hidden && File.GetAttributes(f) != FileAttributes.System) { string name = ""; foreach (string p in f.Split('\\')) if (p.Contains(".")) name = p; ImageSource icon = IconManager.GetIcon(f, false, false); if (name != "desktop.ini" && name != "Thumbs.db") colDesktopItems.Add(new DesktopItem() { ItemName = name.Split('.')[0], ItemPath = f, ItemIcon = icon }); } } 

我还使用DispatcherTimer进行自动刷新(间隔= 5秒):

 private void dpt_Tick(object sender, EventArgs e) { if (dPath != null) { if (GetContent(dPath).ToString() != diCollection.ToString()) { diCollection.Clear(); foreach (DesktopItem i in GetContent(dPath)) diCollection.Add(i); } } } 

diCollection是包含要显示的元素的集合, dPath是从中显示文件的目录的路径。

但是有两个问题:

  • 当我将isDirectory设置为true ,它只返回一个空图标。
  • 过了一会儿,它抛出一个exception:

该值可能不是NULL。 此行中发生exception:

 return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(shfi.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 

我使用相同的方法。 以下是我在我的个人图书馆中设置的方法。

 public static class ImageUtilities { public static System.Drawing.Icon GetRegisteredIcon(string filePath) { var shinfo = new SHfileInfo(); Win32.SHGetFileInfo(filePath, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON); return System.Drawing.Icon.FromHandle(shinfo.hIcon); } } [StructLayout(LayoutKind.Sequential)] 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; } internal sealed class Win32 { public const uint SHGFI_ICON = 0x100; public const uint SHGFI_LARGEICON = 0x0; // large public const uint SHGFI_SMALLICON = 0x1; // small [System.Runtime.InteropServices.DllImport("shell32.dll")] public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHfileInfo psfi, uint cbSizeFileInfo, uint uFlags); } 

用法:

 var icon = ImageUtilites.GetRegisteredIcon(string path) 

我用来为WPF创建一个ImageSource的Extension方法:

 public static System.Windows.Media.ImageSource ToImageSource(this System.Drawing.Bitmap bitmap, int width, int height) { var hBitmap = bitmap.GetHbitmap(); System.Windows.Media.ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, System.Windows.Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromWidthAndHeight(width, height)); if (!DeleteObject(hBitmap)) { throw new System.ComponentModel.Win32Exception(); } return wpfBitmap; } 

我忘了添加这个,我不知道你是否正在使用它..

  [DllImport("gdi32.dll", SetLastError = true)] private static extern bool DeleteObject(IntPtr hObject);