c# / WPF:获取shell使用的图标
本文关键字:图标 shell 获取 WPF | 更新日期: 2023-09-27 18:06:22
我正在尝试开发一个应用程序,可以向您展示目录的内容,如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
时,它只是返回一个空图标。 过了一会儿,它抛出一个异常:
该值不能为NULL。
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的扩展方法:
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);