我有listView
个文档列表。我给每个人分配了一个图标,使用以下方法:
private void SetDocumentIcon(ListViewItem item, FileInfo file)
{
Icon iconForFile = Icon.ExtractAssociatedIcon(file.FullName);
if (!documentsIconsImageList.Images.ContainsKey(file.Extension))
{
iconForFile = Icon.ExtractAssociatedIcon(file.FullName);
documentsIconsImageList.Images.Add(file.Extension, iconForFile);
}
item.ImageKey = file.Extension;
}
我尝试将此方法用于文件夹,但失败了。据我所知,问题是Icon.ExtractAssociatedIcon
用于文件而不是文件夹。那么如何提取文件夹的图标呢?
感谢。
答案 0 :(得分:2)
我打赌还有其他方法,但我认为最容易实现的只是在您创建的临时文件夹上使用SHGetFileInfo
win api函数。示例代码:
public static class DefaultIcons
{
private static readonly Lazy<Icon> _lazyFolderIcon = new Lazy<Icon>(FetchIcon, true);
public static Icon FolderLarge
{
get { return _lazyFolderIcon.Value; }
}
private static Icon FetchIcon()
{
var tmpDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())).FullName;
var icon = ExtractFromPath(tmpDir);
Directory.Delete(tmpDir);
return icon;
}
private static Icon ExtractFromPath(string path)
{
SHFILEINFO shinfo = new SHFILEINFO();
SHGetFileInfo(
path,
0, ref shinfo, (uint)Marshal.SizeOf(shinfo),
SHGFI_ICON | SHGFI_LARGEICON);
return System.Drawing.Icon.FromHandle(shinfo.hIcon);
}
//Struct used by SHGetFileInfo function
[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.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0;
private const uint SHGFI_SMALLICON = 0x000000001;
}
用法只是
var icon = DefaultIcons.FolderLarge
为小图标添加属性也很简单。
答案 1 :(得分:2)
SHGetStockIconInfo
是正确的方法,并且不需要添加不必要的文件IO。没什么比SHGetFileInfo
复杂的了。
这是一个示例类,其结构类似于Evk的类。注意一些重要的事情:
SHGetStockIconInfo
(甚至是SHGetFileInfo
)获得图标句柄时,必须通过调用DestroyIcon()
清除本机图标 ,否则会造成资源泄漏。Icon.FromHandle()
创建图标时,该对象将存储您赋予它的句柄,并将其用于以后的操作。这意味着,如果您立即调用DestroyIcon()
,然后尝试使用刚刚创建的图标进行操作,则会导致异常。您可以使用Clone()
来获得不依赖于原始本机句柄的Icon
。public static class DefaultIcons
{
private static Icon folderIcon;
public static Icon FolderLarge => folderIcon ?? (folderIcon = GetStockIcon(SHSIID_FOLDER, SHGSI_LARGEICON));
private static Icon GetStockIcon(uint type, uint size)
{
var info = new SHSTOCKICONINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
SHGetStockIconInfo(type, SHGSI_ICON | size, ref info);
var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone(); // Get a copy that doesn't use the original handle
DestroyIcon(info.hIcon); // Clean up native icon to prevent resource leak
return icon;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO
{
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
private const uint SHSIID_FOLDER = 0x3;
private const uint SHGSI_ICON = 0x100;
private const uint SHGSI_LARGEICON = 0x0;
private const uint SHGSI_SMALLICON = 0x1;
}