Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#/WPF:获取shell使用的图标_C#_Wpf_File_Directory_Icons - Fatal编程技术网

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

C#/WPF:获取shell使用的图标,c#,wpf,file,directory,icons,C#,Wpf,File,Directory,Icons,我正在尝试开发一个应用程序,可以向您显示目录的内容,如Windows资源管理器(带有文件名和图标)。我目前正在使用以下代码: public class IconManager { public static ImageSource GetIcon(string path, bool smallIcon, bool isDirectory) { uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; if

我正在尝试开发一个应用程序,可以向您显示目录的内容,如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 });
            }
        }
我还使用
Dispatchermer
自动刷新(间隔=5秒):

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

但有两个问题:

  • 当我将
    isDirectory
    设置为
    true
    时,它只返回一个空图标
  • 一段时间后,它抛出一个异常:

    该值不能为NULL
例外情况发生在这一行:


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

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);

它可以工作,但过了一段时间(当文件夹中有许多图标时),会抛出一个
System.ArgumentException
异常(表示传输到
图标的Win32句柄无效)。它将被抛出到哪里?你能得到stacktrace吗?@JanBöhm你可能不会对不再使用的图标调用
DestroyIcon
,最终会耗尽GDI资源。
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);